diff --git a/docs/api-operation.md b/docs/api-operation.md index 41aee64db..9d03d7ba1 100644 --- a/docs/api-operation.md +++ b/docs/api-operation.md @@ -129,13 +129,41 @@ When used without parameters, performs a fast, mild sharpen of the output image. When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space. Separate control over the level of sharpening in "flat" and "jagged" areas is available. +See [libvips sharpen][8] operation. + ### Parameters -* `sigma` **[number][1]?** the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`. -* `flat` **[number][1]** the level of sharpening to apply to "flat" areas. (optional, default `1.0`) -* `jagged` **[number][1]** the level of sharpening to apply to "jagged" areas. (optional, default `2.0`) +* `options` **[Object][2]?** if present, is an Object with optional attributes. - + * `options.sigma` **[number][1]?** the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`. + * `options.m1` **[number][1]** the level of sharpening to apply to "flat" areas. (optional, default `1.0`) + * `options.m2` **[number][1]** the level of sharpening to apply to "jagged" areas. (optional, default `2.0`) + * `options.x1` **[number][1]** threshold between "flat" and "jagged" (optional, default `2.0`) + * `options.y2` **[number][1]** maximum amount of brightening. (optional, default `10.0`) + * `options.y3` **[number][1]** maximum amount of darkening. (optional, default `20.0`) + +### Examples + +```javascript +const data = await sharp(input).sharpen().toBuffer(); +``` + +```javascript +const data = await sharp(input).sharpen({ sigma: 2 }).toBuffer(); +``` + +```javascript +const data = await sharp(input) + .sharpen({ + sigma: 2, + m1: 0 + m2: 3, + x1: 3, + y2: 15, + y3: 15, + }) + .toBuffer(); +``` * Throws **[Error][5]** Invalid parameters @@ -190,7 +218,7 @@ Returns **Sharp** Merge alpha transparency channel, if any, with a background, then remove the alpha channel. -See also [removeAlpha][8]. +See also [removeAlpha][9]. ### Parameters @@ -264,7 +292,7 @@ Returns **Sharp** ## clahe Perform contrast limiting adaptive histogram equalization -[CLAHE][9]. +[CLAHE][10]. This will, in general, enhance the clarity of the image by bringing out darker details. @@ -349,7 +377,7 @@ the selected bitwise boolean `operation` between the corresponding pixels of the ### Parameters -* `operand` **([Buffer][10] | [string][3])** Buffer containing image data or string containing the path to an image file. +* `operand` **([Buffer][11] | [string][3])** Buffer containing image data or string containing the path to an image file. * `operator` **[string][3]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively. * `options` **[Object][2]?** @@ -474,8 +502,10 @@ Returns **Sharp** [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array -[8]: /api-channel#removealpha +[8]: https://www.libvips.org/API/current/libvips-convolution.html#vips-sharpen + +[9]: /api-channel#removealpha -[9]: https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE +[10]: https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE -[10]: https://nodejs.org/api/buffer.html +[11]: https://nodejs.org/api/buffer.html diff --git a/docs/changelog.md b/docs/changelog.md index 25dbe2cd7..b7c6a3350 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,12 @@ Requires libvips v8.12.2 ### v0.30.3 - TBD +* Allow `sharpen` options to be provided more consistently as an Object. + [#2561](https://github.com/lovell/sharp/issues/2561) + +* Expose `x1`, `y2` and `y3` parameters of `sharpen` operation. + [#2935](https://github.com/lovell/sharp/issues/2935) + * Prevent double unpremultiply with some composite blend modes (regression in 0.30.2). [#3118](https://github.com/lovell/sharp/issues/3118) diff --git a/docs/search-index.json b/docs/search-index.json index 4624cc790..40d552822 100644 --- a/docs/search-index.json +++ b/docs/search-index.json @@ -1 +1 @@ -[{"t":"Prerequisites","d":"Node.js 12.13.0","k":"prerequisites node","l":"/install#prerequisites"},{"t":"Prebuilt binaries","d":"Ready-compiled sharp and libvips binaries are provided for use on the most common platforms macOS x64 10.13 macOS ARM64 Linux x64 glibc 2.17, musl 1.1.24, CPU with SSE4.2 Linux ARM","k":"prebuilt binaries compiled sharp libvips common platforms macos arm linux glibc musl cpu sse","l":"/install#prebuilt-binaries"},{"t":"Common problems","d":"The architecture and platform of Node.js used for npm install must be the same as the architecture and platform of Node.js used at runtime. See the cross-platform","k":"common problems architecture platform node npm install runtime cross","l":"/install#common-problems"},{"t":"Apple M1","d":"Prebuilt sharp and libvips binaries have been provided for macOS on ARM64 since sharp v0.29.0.","k":"apple prebuilt sharp libvips binaries macos arm","l":"/install#apple-m1"},{"t":"Custom libvips","d":"To use a custom, globally-installed version of libvips instead of the provided binaries, make sure it is at least the version listed under config.libvips in the package.json file a","k":"custom libvips globally installed version instead binaries listed config package json file","l":"/install#custom-libvips"},{"t":"Building from source","d":"This module will be compiled from source at npm install time when a globally-installed libvips is detected set the SHARP_IGNORE_GLOBAL_LIBVIPS environment variable to skip this, pr","k":"building source module compiled npm install time globally installed libvips detected environment variable skip","l":"/install#building-from-source"},{"t":"Custom prebuilt binaries","d":"This is an advanced approach that most people will not require. To install the prebuilt sharp binaries from a custom URL, set the sharp_binary_host npm config option or the npm_con","k":"custom prebuilt binaries advanced approach people require install sharp url npm config option npmcon","l":"/install#custom-prebuilt-binaries"},{"t":"Chinese mirror","d":"A mirror site based in China, provided by Alibaba, contains binaries for both sharp and libvips. To use this either set the following configuration sh npm config set sharp_binary_h","k":"chinese mirror china alibaba binaries sharp libvips configuration npm config sharpbinaryh","l":"/install#chinese-mirror"},{"t":"FreeBSD","d":"The vips package must be installed before npm install is run. sh pkg install -y pkgconf vips sh cd /usr/ports/graphics/vips/ make install clean","k":"freebsd vips package installed npm install run pkg pkgconf usr ports graphics clean","l":"/install#freebsd"},{"t":"Linux memory allocator","d":"The default memory allocator on most glibc-based Linux systems e.g. Debian, Red Hat is unsuitable for long-running, multi-threaded processes that involve lots of small memory alloc","k":"linux memory allocator glibc systems debian red hat long running multi threaded processes small alloc","l":"/install#linux-memory-allocator"},{"t":"Heroku","d":"Add the jemalloc buildpack to reduce the effects of memory fragmentation. Set NODE_MODULES_CACHE","k":"heroku add jemalloc buildpack reduce effects memory fragmentation","l":"/install#heroku"},{"t":"AWS Lambda","d":"The node_modules directory of the deployment package must include binaries for the Linux x64 platform. When building your deployment package on machines other than Linux x64 glibc,","k":"aws lambda nodemodules directory deployment package include binaries linux platform building your machines glibc","l":"/install#aws-lambda"},{"t":"Webpack","d":"Ensure sharp is added to the externals configuration. js externals sharp commonjs sharp","k":"webpack sharp added externals configuration commonjs","l":"/install#webpack"},{"t":"Worker threads","d":"The main thread must call requiresharp before worker threads are created to ensure shared libraries remain loaded in memory until after all threads are complete.","k":"worker threads main thread requiresharp created shared libraries remain loaded memory complete","l":"/install#worker-threads"},{"t":"Canvas and Windows","d":"The prebuilt binaries provided by canvas for Windows depend on the unmaintained GTK 2, last updated in 2011. These conflict with the modern, up-to-date binaries provided by sharp.","k":"canvas windows prebuilt binaries depend gtk updated conflict modern sharp","l":"/install#canvas-and-windows"},{"t":"Sharp","d":"Constructor factory to create an instance of sharp, to which further methods are chained.","k":"sharp constructor factory create instance further methods chained","l":"/api-constructor#sharp"},{"t":"clone","d":"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 mult","k":"clone snapshot sharp instance returning new cloned instances inherit input parent multiple output streams mult","l":"/api-constructor#clone"},{"t":"metadata","d":"Fast access to uncached image metadata without decoding any compressed pixel data.","k":"metadata fast access uncached decoding compressed pixel data","l":"/api-input#metadata"},{"t":"stats","d":"Access to pixel-derived image statistics for every channel in the image. A Promise is returned when callback is not provided.","k":"stats access pixel derived statistics channel promise","l":"/api-input#stats"},{"t":"toFile","d":"Write output image data to a file.","k":"tofile write output data file","l":"/api-output#tofile"},{"t":"toBuffer","d":"Write output to a Buffer. JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.","k":"tobuffer write output buffer jpeg png webp avif tiff gif raw pixel data","l":"/api-output#tobuffer"},{"t":"withMetadata","d":"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 p","k":"withmetadata include metadata exif xmp iptc input output convert add web friendly srgb icc profile custom","l":"/api-output#withmetadata"},{"t":"toFormat","d":"Force output to a given format.","k":"toformat force output format","l":"/api-output#toformat"},{"t":"jpeg","d":"Use these JPEG options for output image.","k":"jpeg output quality progressive optimisecoding optimizecoding mozjpeg optimisescans optimizescans force","l":"/api-output#jpeg"},{"t":"png","d":"Use these PNG options for output image.","k":"png output","l":"/api-output#png"},{"t":"webp","d":"Use these WebP options for output image.","k":"webp output quality alphaquality lossless nearlossless smartsubsample effort loop delay force","l":"/api-output#webp"},{"t":"gif","d":"Use these GIF options for the output image.","k":"gif output","l":"/api-output#gif"},{"t":"tiff","d":"Use these TIFF options for output image.","k":"tiff output","l":"/api-output#tiff"},{"t":"avif","d":"Use these AVIF options for output image.","k":"avif output","l":"/api-output#avif"},{"t":"heif","d":"Use these HEIF options for output image.","k":"heif output","l":"/api-output#heif"},{"t":"raw","d":"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 colourspace","k":"raw force output uncompressed pixel data ordering left right top bottom padding channel rgb rgba greyscale colourspace depth size overlap angle background skipblanks container layout centre center","l":"/api-output#raw"},{"t":"timeout","d":"Set a timeout for processing, in seconds. Use a value of zero to continue processing indefinitely, the default behaviour.","k":"timeout processing seconds zero continue indefinitely behaviour","l":"/api-output#timeout"},{"t":"resize","d":"Resize image to width, height or width x height.","k":"resize width height","l":"/api-resize#resize"},{"t":"extend","d":"Extends/pads the edges of the image with the provided background colour. This operation will always occur after resizing and extraction, if any.","k":"extend extends pads edges background colour operation resizing extraction","l":"/api-resize#extend"},{"t":"extract","d":"Extract/crop a region of the image.","k":"extract crop region","l":"/api-resize#extract"},{"t":"trim","d":"Trim boring pixels from all edges that contain values similar to the top-left pixel. Images consisting entirely of a single colour will calculate boring using the alpha channel, if","k":"trim boring pixels edges contain similar top left pixel images consisting single colour calculate alpha channel","l":"/api-resize#trim"},{"t":"composite","d":"Composite images over the processed resized, extracted etc. image.","k":"composite images processed resized extracted","l":"/api-composite#composite"},{"t":"rotate","d":"Rotate the output image by either an explicit angle or auto-orient based on the EXIF Orientation tag.","k":"rotate output explicit angle auto orient exif orientation tag","l":"/api-operation#rotate"},{"t":"flip","d":"Flip the image about the vertical Y axis. This always occurs after rotation, if any. The use of flip implies the removal of the EXIF Orientation tag, if any.","k":"flip vertical axis rotation removal exif orientation tag","l":"/api-operation#flip"},{"t":"flop","d":"Flop the image about the horizontal X axis. This always occurs after rotation, if any. The use of flop implies the removal of the EXIF Orientation tag, if any.","k":"flop horizontal axis rotation removal exif orientation tag","l":"/api-operation#flop"},{"t":"affine","d":"Perform an affine transform on an image. This operation will always occur after resizing, extraction and rotation, if any.","k":"affine transform operation resizing extraction rotation","l":"/api-operation#affine"},{"t":"sharpen","d":"Sharpen the image. When used without parameters, performs a fast, mild sharpen of the output image. When a sigma is provided, performs a slower, more accurate sharpen of the L chan","k":"sharpen parameters fast mild output sigma slower accurate chan","l":"/api-operation#sharpen"},{"t":"median","d":"Apply median filter. When used without parameters the default window is 3x3.","k":"median apply filter parameters window","l":"/api-operation#median"},{"t":"blur","d":"Blur the image.","k":"blur","l":"/api-operation#blur"},{"t":"flatten","d":"Merge alpha transparency channel, if any, with a background, then remove the alpha channel.","k":"flatten merge alpha transparency channel background remove","l":"/api-operation#flatten"},{"t":"gamma","d":"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","k":"gamma apply correction reducing encoding darken pre resize factor increasing brighten post improve","l":"/api-operation#gamma"},{"t":"negate","d":"Produce the negative of the image.","k":"negate negative alpha","l":"/api-operation#negate"},{"t":"normalise","d":"Enhance output image contrast by stretching its luminance to cover the full dynamic range.","k":"normalise enhance output contrast stretching luminance cover full dynamic range","l":"/api-operation#normalise"},{"t":"normalize","d":"Alternative spelling of normalise.","k":"normalize normalise","l":"/api-operation#normalize"},{"t":"clahe","d":"Perform contrast limiting adaptive histogram equalization CLAHE9.","k":"clahe contrast limiting adaptive histogram equalization","l":"/api-operation#clahe"},{"t":"convolve","d":"Convolve the image with the specified kernel.","k":"convolve kernel","l":"/api-operation#convolve"},{"t":"threshold","d":"Any pixel value greater than or equal to the threshold value will be set to 255, otherwise it will be set to 0.","k":"threshold pixel greater equal otherwise greyscale grayscale","l":"/api-operation#threshold"},{"t":"boolean","d":"Perform a bitwise boolean operation with operand image.","k":"boolean bitwise operation operand","l":"/api-operation#boolean"},{"t":"linear","d":"Apply the linear formula a input b to the image levels adjustment","k":"linear apply formula input levels adjustment","l":"/api-operation#linear"},{"t":"recomb","d":"Recomb the image with the specified matrix.","k":"recomb matrix","l":"/api-operation#recomb"},{"t":"modulate","d":"Transforms the image using brightness, saturation, hue rotation, and lightness. Brightness and lightness both operate on luminance, with the difference being that brightness is mul","k":"modulate transforms brightness saturation hue rotation lightness operate luminance difference being mul","l":"/api-operation#modulate"},{"t":"removeAlpha","d":"Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.","k":"removealpha remove alpha channel","l":"/api-channel#removealpha"},{"t":"ensureAlpha","d":"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. This is a n","k":"ensurealpha output alpha transparency channel missing added level defaulting fully opaque","l":"/api-channel#ensurealpha"},{"t":"extractChannel","d":"Extract a single channel from a multi-channel image.","k":"extractchannel extract single channel multi","l":"/api-channel#extractchannel"},{"t":"joinChannel","d":"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-friendl","k":"joinchannel join one channels meaning added depends output colourspace tocolourspace web friendl","l":"/api-channel#joinchannel"},{"t":"bandbool","d":"Perform a bitwise boolean operation on all input image channels bands to produce a single channel output image.","k":"bandbool bitwise boolean operation input channels bands single channel output","l":"/api-channel#bandbool"},{"t":"tint","d":"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.","k":"tint chroma preserving luminance alpha channel present unchanged operation","l":"/api-colour#tint"},{"t":"greyscale","d":"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 re","k":"greyscale convert bit shades grey linear operation input colour space srgb gamma best","l":"/api-colour#greyscale"},{"t":"grayscale","d":"Alternative spelling of greyscale.","k":"grayscale greyscale","l":"/api-colour#grayscale"},{"t":"pipelineColourspace","d":"Set the pipeline colourspace.","k":"pipeline colourspace","l":"/api-colour#pipelinecolourspace"},{"t":"pipelineColorspace","d":"Alternative spelling of pipelineColourspace.","k":"","l":"/api-colour#pipelinecolorspace"},{"t":"toColourspace","d":"Set the output colourspace. By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.","k":"tocolourspace output colourspace web friendly srgb additional channels interpreted alpha","l":"/api-colour#tocolourspace"},{"t":"toColorspace","d":"Alternative spelling of toColourspace.","k":"tocolorspace tocolourspace","l":"/api-colour#tocolorspace"},{"t":"format","d":"An Object containing nested boolean values representing the available input and output formats/methods.","k":"format object nested boolean representing available input output formats methods","l":"/api-utility#format"},{"t":"interpolators","d":"An Object containing the available interpolators and their proper values","k":"interpolators object available proper","l":"/api-utility#interpolators"},{"t":"versions","d":"An Object containing the version numbers of libvips and its dependencies.","k":"versions object version numbers libvips dependencies","l":"/api-utility#versions"},{"t":"vendor","d":"An Object containing the platform and architecture of the current and installed vendored binaries.","k":"vendor object platform architecture installed vendored binaries","l":"/api-utility#vendor"},{"t":"cache","d":"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","k":"cache limits libvips operation existing entries trimmed change method returns memory files items","l":"/api-utility#cache"},{"t":"concurrency","d":"Gets or, when a concurrency is provided, sets the number of threads libvips should create to process each image.","k":"concurrency number threads libvips create process","l":"/api-utility#concurrency"},{"t":"queue","d":"An EventEmitter that emits a change event when a task is either","k":"queue eventemitter emits change event","l":"/api-utility#queue"},{"t":"counters","d":"Provides access to internal task counters.","k":"counters provides access internal","l":"/api-utility#counters"},{"t":"simd","d":"Get and set use of SIMD vector unit instructions. Requires libvips to have been compiled with liborc support.","k":"simd vector unit instructions libvips compiled liborc","l":"/api-utility#simd"}] \ No newline at end of file +[{"t":"Prerequisites","d":"Node.js 12.13.0","k":"prerequisites node","l":"/install#prerequisites"},{"t":"Prebuilt binaries","d":"Ready-compiled sharp and libvips binaries are provided for use on the most common platforms macOS x64 10.13 macOS ARM64 Linux x64 glibc 2.17, musl 1.1.24, CPU with SSE4.2 Linux ARM","k":"prebuilt binaries compiled sharp libvips common platforms macos arm linux glibc musl cpu sse","l":"/install#prebuilt-binaries"},{"t":"Common problems","d":"The architecture and platform of Node.js used for npm install must be the same as the architecture and platform of Node.js used at runtime. See the cross-platform","k":"common problems architecture platform node npm install runtime cross","l":"/install#common-problems"},{"t":"Apple M1","d":"Prebuilt sharp and libvips binaries have been provided for macOS on ARM64 since sharp v0.29.0.","k":"apple prebuilt sharp libvips binaries macos arm","l":"/install#apple-m1"},{"t":"Custom libvips","d":"To use a custom, globally-installed version of libvips instead of the provided binaries, make sure it is at least the version listed under config.libvips in the package.json file a","k":"custom libvips globally installed version instead binaries listed config package json file","l":"/install#custom-libvips"},{"t":"Building from source","d":"This module will be compiled from source at npm install time when a globally-installed libvips is detected set the SHARP_IGNORE_GLOBAL_LIBVIPS environment variable to skip this, pr","k":"building source module compiled npm install time globally installed libvips detected environment variable skip","l":"/install#building-from-source"},{"t":"Custom prebuilt binaries","d":"This is an advanced approach that most people will not require. To install the prebuilt sharp binaries from a custom URL, set the sharp_binary_host npm config option or the npm_con","k":"custom prebuilt binaries advanced approach people require install sharp url npm config option npmcon","l":"/install#custom-prebuilt-binaries"},{"t":"Chinese mirror","d":"A mirror site based in China, provided by Alibaba, contains binaries for both sharp and libvips. To use this either set the following configuration sh npm config set sharp_binary_h","k":"chinese mirror china alibaba binaries sharp libvips configuration npm config sharpbinaryh","l":"/install#chinese-mirror"},{"t":"FreeBSD","d":"The vips package must be installed before npm install is run. sh pkg install -y pkgconf vips sh cd /usr/ports/graphics/vips/ make install clean","k":"freebsd vips package installed npm install run pkg pkgconf usr ports graphics clean","l":"/install#freebsd"},{"t":"Linux memory allocator","d":"The default memory allocator on most glibc-based Linux systems e.g. Debian, Red Hat is unsuitable for long-running, multi-threaded processes that involve lots of small memory alloc","k":"linux memory allocator glibc systems debian red hat long running multi threaded processes small alloc","l":"/install#linux-memory-allocator"},{"t":"Heroku","d":"Add the jemalloc buildpack to reduce the effects of memory fragmentation. Set NODE_MODULES_CACHE","k":"heroku add jemalloc buildpack reduce effects memory fragmentation","l":"/install#heroku"},{"t":"AWS Lambda","d":"The node_modules directory of the deployment package must include binaries for the Linux x64 platform. When building your deployment package on machines other than Linux x64 glibc,","k":"aws lambda nodemodules directory deployment package include binaries linux platform building your machines glibc","l":"/install#aws-lambda"},{"t":"Webpack","d":"Ensure sharp is added to the externals configuration. js externals sharp commonjs sharp","k":"webpack sharp added externals configuration commonjs","l":"/install#webpack"},{"t":"Worker threads","d":"The main thread must call requiresharp before worker threads are created to ensure shared libraries remain loaded in memory until after all threads are complete.","k":"worker threads main thread requiresharp created shared libraries remain loaded memory complete","l":"/install#worker-threads"},{"t":"Canvas and Windows","d":"The prebuilt binaries provided by canvas for Windows depend on the unmaintained GTK 2, last updated in 2011. These conflict with the modern, up-to-date binaries provided by sharp.","k":"canvas windows prebuilt binaries depend gtk updated conflict modern sharp","l":"/install#canvas-and-windows"},{"t":"Sharp","d":"Constructor factory to create an instance of sharp, to which further methods are chained.","k":"sharp constructor factory create instance further methods chained","l":"/api-constructor#sharp"},{"t":"clone","d":"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 mult","k":"clone snapshot sharp instance returning new cloned instances inherit input parent multiple output streams mult","l":"/api-constructor#clone"},{"t":"metadata","d":"Fast access to uncached image metadata without decoding any compressed pixel data.","k":"metadata fast access uncached decoding compressed pixel data","l":"/api-input#metadata"},{"t":"stats","d":"Access to pixel-derived image statistics for every channel in the image. A Promise is returned when callback is not provided.","k":"stats access pixel derived statistics channel promise","l":"/api-input#stats"},{"t":"toFile","d":"Write output image data to a file.","k":"tofile write output data file","l":"/api-output#tofile"},{"t":"toBuffer","d":"Write output to a Buffer. JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.","k":"tobuffer write output buffer jpeg png webp avif tiff gif raw pixel data","l":"/api-output#tobuffer"},{"t":"withMetadata","d":"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 p","k":"withmetadata include metadata exif xmp iptc input output convert add web friendly srgb icc profile custom","l":"/api-output#withmetadata"},{"t":"toFormat","d":"Force output to a given format.","k":"toformat force output format","l":"/api-output#toformat"},{"t":"jpeg","d":"Use these JPEG options for output image.","k":"jpeg output quality progressive optimisecoding optimizecoding mozjpeg optimisescans optimizescans force","l":"/api-output#jpeg"},{"t":"png","d":"Use these PNG options for output image.","k":"png output","l":"/api-output#png"},{"t":"webp","d":"Use these WebP options for output image.","k":"webp output quality alphaquality lossless nearlossless smartsubsample effort loop delay force","l":"/api-output#webp"},{"t":"gif","d":"Use these GIF options for the output image.","k":"gif output","l":"/api-output#gif"},{"t":"tiff","d":"Use these TIFF options for output image.","k":"tiff output","l":"/api-output#tiff"},{"t":"avif","d":"Use these AVIF options for output image.","k":"avif output","l":"/api-output#avif"},{"t":"heif","d":"Use these HEIF options for output image.","k":"heif output","l":"/api-output#heif"},{"t":"raw","d":"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 colourspace","k":"raw force output uncompressed pixel data ordering left right top bottom padding channel rgb rgba greyscale colourspace depth size overlap angle background skipblanks container layout centre center","l":"/api-output#raw"},{"t":"timeout","d":"Set a timeout for processing, in seconds. Use a value of zero to continue processing indefinitely, the default behaviour.","k":"timeout processing seconds zero continue indefinitely behaviour","l":"/api-output#timeout"},{"t":"resize","d":"Resize image to width, height or width x height.","k":"resize width height","l":"/api-resize#resize"},{"t":"extend","d":"Extends/pads the edges of the image with the provided background colour. This operation will always occur after resizing and extraction, if any.","k":"extend extends pads edges background colour operation resizing extraction","l":"/api-resize#extend"},{"t":"extract","d":"Extract/crop a region of the image.","k":"extract crop region","l":"/api-resize#extract"},{"t":"trim","d":"Trim boring pixels from all edges that contain values similar to the top-left pixel. Images consisting entirely of a single colour will calculate boring using the alpha channel, if","k":"trim boring pixels edges contain similar top left pixel images consisting single colour calculate alpha channel","l":"/api-resize#trim"},{"t":"composite","d":"Composite images over the processed resized, extracted etc. image.","k":"composite images processed resized extracted","l":"/api-composite#composite"},{"t":"rotate","d":"Rotate the output image by either an explicit angle or auto-orient based on the EXIF Orientation tag.","k":"rotate output explicit angle auto orient exif orientation tag","l":"/api-operation#rotate"},{"t":"flip","d":"Flip the image about the vertical Y axis. This always occurs after rotation, if any. The use of flip implies the removal of the EXIF Orientation tag, if any.","k":"flip vertical axis rotation removal exif orientation tag","l":"/api-operation#flip"},{"t":"flop","d":"Flop the image about the horizontal X axis. This always occurs after rotation, if any. The use of flop implies the removal of the EXIF Orientation tag, if any.","k":"flop horizontal axis rotation removal exif orientation tag","l":"/api-operation#flop"},{"t":"affine","d":"Perform an affine transform on an image. This operation will always occur after resizing, extraction and rotation, if any.","k":"affine transform operation resizing extraction rotation","l":"/api-operation#affine"},{"t":"sharpen","d":"Sharpen the image. When used without parameters, performs a fast, mild sharpen of the output image. When a sigma is provided, performs a slower, more accurate sharpen of the L chan","k":"sharpen parameters fast mild output sigma slower accurate chan","l":"/api-operation#sharpen"},{"t":"median","d":"Apply median filter. When used without parameters the default window is 3x3.","k":"median apply filter parameters window","l":"/api-operation#median"},{"t":"blur","d":"Blur the image.","k":"blur","l":"/api-operation#blur"},{"t":"flatten","d":"Merge alpha transparency channel, if any, with a background, then remove the alpha channel.","k":"flatten merge alpha transparency channel background remove","l":"/api-operation#flatten"},{"t":"gamma","d":"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","k":"gamma apply correction reducing encoding darken pre resize factor increasing brighten post improve","l":"/api-operation#gamma"},{"t":"negate","d":"Produce the negative of the image.","k":"negate negative alpha","l":"/api-operation#negate"},{"t":"normalise","d":"Enhance output image contrast by stretching its luminance to cover the full dynamic range.","k":"normalise enhance output contrast stretching luminance cover full dynamic range","l":"/api-operation#normalise"},{"t":"normalize","d":"Alternative spelling of normalise.","k":"normalize normalise","l":"/api-operation#normalize"},{"t":"clahe","d":"Perform contrast limiting adaptive histogram equalization CLAHE10.","k":"clahe contrast limiting adaptive histogram equalization","l":"/api-operation#clahe"},{"t":"convolve","d":"Convolve the image with the specified kernel.","k":"convolve kernel","l":"/api-operation#convolve"},{"t":"threshold","d":"Any pixel value greater than or equal to the threshold value will be set to 255, otherwise it will be set to 0.","k":"threshold pixel greater equal otherwise greyscale grayscale","l":"/api-operation#threshold"},{"t":"boolean","d":"Perform a bitwise boolean operation with operand image.","k":"boolean bitwise operation operand","l":"/api-operation#boolean"},{"t":"linear","d":"Apply the linear formula a input b to the image levels adjustment","k":"linear apply formula input levels adjustment","l":"/api-operation#linear"},{"t":"recomb","d":"Recomb the image with the specified matrix.","k":"recomb matrix","l":"/api-operation#recomb"},{"t":"modulate","d":"Transforms the image using brightness, saturation, hue rotation, and lightness. Brightness and lightness both operate on luminance, with the difference being that brightness is mul","k":"modulate transforms brightness saturation hue rotation lightness operate luminance difference being mul","l":"/api-operation#modulate"},{"t":"removeAlpha","d":"Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.","k":"removealpha remove alpha channel","l":"/api-channel#removealpha"},{"t":"ensureAlpha","d":"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. This is a n","k":"ensurealpha output alpha transparency channel missing added level defaulting fully opaque","l":"/api-channel#ensurealpha"},{"t":"extractChannel","d":"Extract a single channel from a multi-channel image.","k":"extractchannel extract single channel multi","l":"/api-channel#extractchannel"},{"t":"joinChannel","d":"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-friendl","k":"joinchannel join one channels meaning added depends output colourspace tocolourspace web friendl","l":"/api-channel#joinchannel"},{"t":"bandbool","d":"Perform a bitwise boolean operation on all input image channels bands to produce a single channel output image.","k":"bandbool bitwise boolean operation input channels bands single channel output","l":"/api-channel#bandbool"},{"t":"tint","d":"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.","k":"tint chroma preserving luminance alpha channel present unchanged operation","l":"/api-colour#tint"},{"t":"greyscale","d":"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 re","k":"greyscale convert bit shades grey linear operation input colour space srgb gamma best","l":"/api-colour#greyscale"},{"t":"grayscale","d":"Alternative spelling of greyscale.","k":"grayscale greyscale","l":"/api-colour#grayscale"},{"t":"pipelineColourspace","d":"Set the pipeline colourspace.","k":"pipeline colourspace","l":"/api-colour#pipelinecolourspace"},{"t":"pipelineColorspace","d":"Alternative spelling of pipelineColourspace.","k":"","l":"/api-colour#pipelinecolorspace"},{"t":"toColourspace","d":"Set the output colourspace. By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.","k":"tocolourspace output colourspace web friendly srgb additional channels interpreted alpha","l":"/api-colour#tocolourspace"},{"t":"toColorspace","d":"Alternative spelling of toColourspace.","k":"tocolorspace tocolourspace","l":"/api-colour#tocolorspace"},{"t":"format","d":"An Object containing nested boolean values representing the available input and output formats/methods.","k":"format object nested boolean representing available input output formats methods","l":"/api-utility#format"},{"t":"interpolators","d":"An Object containing the available interpolators and their proper values","k":"interpolators object available proper","l":"/api-utility#interpolators"},{"t":"versions","d":"An Object containing the version numbers of libvips and its dependencies.","k":"versions object version numbers libvips dependencies","l":"/api-utility#versions"},{"t":"vendor","d":"An Object containing the platform and architecture of the current and installed vendored binaries.","k":"vendor object platform architecture installed vendored binaries","l":"/api-utility#vendor"},{"t":"cache","d":"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","k":"cache limits libvips operation existing entries trimmed change method returns memory files items","l":"/api-utility#cache"},{"t":"concurrency","d":"Gets or, when a concurrency is provided, sets the number of threads libvips should create to process each image.","k":"concurrency number threads libvips create process","l":"/api-utility#concurrency"},{"t":"queue","d":"An EventEmitter that emits a change event when a task is either","k":"queue eventemitter emits change event","l":"/api-utility#queue"},{"t":"counters","d":"Provides access to internal task counters.","k":"counters provides access internal","l":"/api-utility#counters"},{"t":"simd","d":"Get and set use of SIMD vector unit instructions. Requires libvips to have been compiled with liborc support.","k":"simd vector unit instructions libvips compiled liborc","l":"/api-utility#simd"}] \ No newline at end of file diff --git a/lib/constructor.js b/lib/constructor.js index 5d1d63b10..503074b13 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -186,8 +186,11 @@ const Sharp = function (input, options) { medianSize: 0, blurSigma: 0, sharpenSigma: 0, - sharpenFlat: 1, - sharpenJagged: 2, + sharpenM1: 1, + sharpenM2: 2, + sharpenX1: 2, + sharpenY2: 10, + sharpenY3: 20, threshold: 0, thresholdGrayscale: true, trimThreshold: 0, diff --git a/lib/operation.js b/lib/operation.js index 9e1e041cb..c1e086148 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -185,40 +185,105 @@ function affine (matrix, options) { * When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space. * Separate control over the level of sharpening in "flat" and "jagged" areas is available. * - * @param {number} [sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`. - * @param {number} [flat=1.0] - the level of sharpening to apply to "flat" areas. - * @param {number} [jagged=2.0] - the level of sharpening to apply to "jagged" areas. + * See {@link https://www.libvips.org/API/current/libvips-convolution.html#vips-sharpen|libvips sharpen} operation. + * + * @example + * const data = await sharp(input).sharpen().toBuffer(); + * + * @example + * const data = await sharp(input).sharpen({ sigma: 2 }).toBuffer(); + * + * @example + * const data = await sharp(input) + * .sharpen({ + * sigma: 2, + * m1: 0 + * m2: 3, + * x1: 3, + * y2: 15, + * y3: 15, + * }) + * .toBuffer(); + * + * @param {Object} [options] - if present, is an Object with optional attributes. + * @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`. + * @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas. + * @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas. + * @param {number} [options.x1=2.0] - threshold between "flat" and "jagged" + * @param {number} [options.y2=10.0] - maximum amount of brightening. + * @param {number} [options.y3=20.0] - maximum amount of darkening. * @returns {Sharp} * @throws {Error} Invalid parameters */ -function sharpen (sigma, flat, jagged) { - if (!is.defined(sigma)) { +function sharpen (options) { + if (!is.defined(options)) { // No arguments: default to mild sharpen this.options.sharpenSigma = -1; - } else if (is.bool(sigma)) { - // Boolean argument: apply mild sharpen? - this.options.sharpenSigma = sigma ? -1 : 0; - } else if (is.number(sigma) && is.inRange(sigma, 0.01, 10000)) { - // Numeric argument: specific sigma - this.options.sharpenSigma = sigma; - // Control over flat areas - if (is.defined(flat)) { - if (is.number(flat) && is.inRange(flat, 0, 10000)) { - this.options.sharpenFlat = flat; + } else if (is.bool(options)) { + // Deprecated boolean argument: apply mild sharpen? + this.options.sharpenSigma = options ? -1 : 0; + } else if (is.number(options) && is.inRange(options, 0.01, 10000)) { + // Deprecated numeric argument: specific sigma + this.options.sharpenSigma = options; + // Deprecated control over flat areas + if (is.defined(arguments[1])) { + if (is.number(arguments[1]) && is.inRange(arguments[1], 0, 10000)) { + this.options.sharpenM1 = arguments[1]; + } else { + throw is.invalidParameterError('flat', 'number between 0 and 10000', arguments[1]); + } + } + // Deprecated control over jagged areas + if (is.defined(arguments[2])) { + if (is.number(arguments[2]) && is.inRange(arguments[2], 0, 10000)) { + this.options.sharpenM2 = arguments[2]; + } else { + throw is.invalidParameterError('jagged', 'number between 0 and 10000', arguments[2]); + } + } + } else if (is.plainObject(options)) { + if (is.number(options.sigma) && is.inRange(options.sigma, 0.01, 10000)) { + this.options.sharpenSigma = options.sigma; + } else { + throw is.invalidParameterError('options.sigma', 'number between 0.01 and 10000', options.sigma); + } + if (is.defined(options.m1)) { + if (is.number(options.m1) && is.inRange(options.m1, 0, 10000)) { + this.options.sharpenM1 = options.m1; + } else { + throw is.invalidParameterError('options.m1', 'number between 0 and 10000', options.m1); + } + } + if (is.defined(options.m2)) { + if (is.number(options.m2) && is.inRange(options.m2, 0, 10000)) { + this.options.sharpenM2 = options.m2; + } else { + throw is.invalidParameterError('options.m2', 'number between 0 and 10000', options.m2); + } + } + if (is.defined(options.x1)) { + if (is.number(options.x1) && is.inRange(options.x1, 0, 10000)) { + this.options.sharpenX1 = options.x1; + } else { + throw is.invalidParameterError('options.x1', 'number between 0 and 10000', options.x1); + } + } + if (is.defined(options.y2)) { + if (is.number(options.y2) && is.inRange(options.y2, 0, 10000)) { + this.options.sharpenY2 = options.y2; } else { - throw is.invalidParameterError('flat', 'number between 0 and 10000', flat); + throw is.invalidParameterError('options.y2', 'number between 0 and 10000', options.y2); } } - // Control over jagged areas - if (is.defined(jagged)) { - if (is.number(jagged) && is.inRange(jagged, 0, 10000)) { - this.options.sharpenJagged = jagged; + if (is.defined(options.y3)) { + if (is.number(options.y3) && is.inRange(options.y3, 0, 10000)) { + this.options.sharpenY3 = options.y3; } else { - throw is.invalidParameterError('jagged', 'number between 0 and 10000', jagged); + throw is.invalidParameterError('options.y3', 'number between 0 and 10000', options.y3); } } } else { - throw is.invalidParameterError('sigma', 'number between 0.01 and 10000', sigma); + throw is.invalidParameterError('sigma', 'number between 0.01 and 10000', options); } return this; } diff --git a/src/operations.cc b/src/operations.cc index 3a3566e00..9877cfda5 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -209,7 +209,8 @@ namespace sharp { /* * Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen. */ - VImage Sharpen(VImage image, double const sigma, double const flat, double const jagged) { + VImage Sharpen(VImage image, double const sigma, double const m1, double const m2, + double const x1, double const y2, double const y3) { if (sigma == -1.0) { // Fast, mild sharpen VImage sharpen = VImage::new_matrixv(3, 3, @@ -224,8 +225,14 @@ namespace sharp { if (colourspaceBeforeSharpen == VIPS_INTERPRETATION_RGB) { colourspaceBeforeSharpen = VIPS_INTERPRETATION_sRGB; } - return image.sharpen( - VImage::option()->set("sigma", sigma)->set("m1", flat)->set("m2", jagged)) + return image + .sharpen(VImage::option() + ->set("sigma", sigma) + ->set("m1", m1) + ->set("m2", m2) + ->set("x1", x1) + ->set("y2", y2) + ->set("y3", y3)) .colourspace(colourspaceBeforeSharpen); } } diff --git a/src/operations.h b/src/operations.h index 6d1f1ca3a..fe0dcd991 100644 --- a/src/operations.h +++ b/src/operations.h @@ -64,7 +64,8 @@ namespace sharp { /* * Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen. */ - VImage Sharpen(VImage image, double const sigma, double const flat, double const jagged); + VImage Sharpen(VImage image, double const sigma, double const m1, double const m2, + double const x1, double const y2, double const y3); /* Threshold an image diff --git a/src/pipeline.cc b/src/pipeline.cc index a08586050..88e39ec11 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -577,7 +577,8 @@ class PipelineWorker : public Napi::AsyncWorker { // Sharpen if (shouldSharpen) { - image = sharp::Sharpen(image, baton->sharpenSigma, baton->sharpenFlat, baton->sharpenJagged); + image = sharp::Sharpen(image, baton->sharpenSigma, baton->sharpenM1, baton->sharpenM2, + baton->sharpenX1, baton->sharpenY2, baton->sharpenY3); } // Composite @@ -1400,8 +1401,11 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { baton->lightness = sharp::AttrAsDouble(options, "lightness"); baton->medianSize = sharp::AttrAsUint32(options, "medianSize"); baton->sharpenSigma = sharp::AttrAsDouble(options, "sharpenSigma"); - baton->sharpenFlat = sharp::AttrAsDouble(options, "sharpenFlat"); - baton->sharpenJagged = sharp::AttrAsDouble(options, "sharpenJagged"); + baton->sharpenM1 = sharp::AttrAsDouble(options, "sharpenM1"); + baton->sharpenM2 = sharp::AttrAsDouble(options, "sharpenM2"); + baton->sharpenX1 = sharp::AttrAsDouble(options, "sharpenX1"); + baton->sharpenY2 = sharp::AttrAsDouble(options, "sharpenY2"); + baton->sharpenY3 = sharp::AttrAsDouble(options, "sharpenY3"); baton->threshold = sharp::AttrAsInt32(options, "threshold"); baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale"); baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold"); diff --git a/src/pipeline.h b/src/pipeline.h index 90e808d92..703d1254c 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -90,8 +90,11 @@ struct PipelineBaton { double lightness; int medianSize; double sharpenSigma; - double sharpenFlat; - double sharpenJagged; + double sharpenM1; + double sharpenM2; + double sharpenX1; + double sharpenY2; + double sharpenY3; int threshold; bool thresholdGrayscale; double trimThreshold; @@ -234,8 +237,11 @@ struct PipelineBaton { lightness(0), medianSize(0), sharpenSigma(0.0), - sharpenFlat(1.0), - sharpenJagged(2.0), + sharpenM1(1.0), + sharpenM2(2.0), + sharpenX1(2.0), + sharpenY2(10.0), + sharpenY3(20.0), threshold(0), thresholdGrayscale(true), trimThreshold(0.0), diff --git a/test/unit/sharpen.js b/test/unit/sharpen.js index ab3b134e5..44ce81ac9 100644 --- a/test/unit/sharpen.js +++ b/test/unit/sharpen.js @@ -45,6 +45,22 @@ describe('Sharpen', function () { }); }); + it('sigma=3.5, m1=2, m2=4', (done) => { + sharp(fixtures.inputJpg) + .resize(320, 240) + .sharpen({ sigma: 3.5, m1: 2, m2: 4 }) + .toBuffer() + .then(data => fixtures.assertSimilar(fixtures.expected('sharpen-5-2-4.jpg'), data, done)); + }); + + it('sigma=3.5, m1=2, m2=4, x1=2, y2=5, y3=25', (done) => { + sharp(fixtures.inputJpg) + .resize(320, 240) + .sharpen({ sigma: 3.5, m1: 2, m2: 4, x1: 2, y2: 5, y3: 25 }) + .toBuffer() + .then(data => fixtures.assertSimilar(fixtures.expected('sharpen-5-2-4.jpg'), data, done)); + }); + if (!process.env.SHARP_TEST_WITHOUT_CACHE) { it('specific radius/levels with alpha channel', function (done) { sharp(fixtures.inputPngWithTransparency) @@ -92,6 +108,36 @@ describe('Sharpen', function () { }); }); + it('invalid options.sigma', () => assert.throws( + () => sharp().sharpen({ sigma: -1 }), + /Expected number between 0\.01 and 10000 for options\.sigma but received -1 of type number/ + )); + + it('invalid options.m1', () => assert.throws( + () => sharp().sharpen({ sigma: 1, m1: -1 }), + /Expected number between 0 and 10000 for options\.m1 but received -1 of type number/ + )); + + it('invalid options.m2', () => assert.throws( + () => sharp().sharpen({ sigma: 1, m2: -1 }), + /Expected number between 0 and 10000 for options\.m2 but received -1 of type number/ + )); + + it('invalid options.x1', () => assert.throws( + () => sharp().sharpen({ sigma: 1, x1: -1 }), + /Expected number between 0 and 10000 for options\.x1 but received -1 of type number/ + )); + + it('invalid options.y2', () => assert.throws( + () => sharp().sharpen({ sigma: 1, y2: -1 }), + /Expected number between 0 and 10000 for options\.y2 but received -1 of type number/ + )); + + it('invalid options.y3', () => assert.throws( + () => sharp().sharpen({ sigma: 1, y3: -1 }), + /Expected number between 0 and 10000 for options\.y3 but received -1 of type number/ + )); + it('sharpened image is larger than non-sharpened', function (done) { sharp(fixtures.inputJpg) .resize(320, 240)