Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@napi-rs/image

Package Overview
Dependencies
Maintainers
2
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@napi-rs/image - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

347

index.d.ts

@@ -6,8 +6,105 @@ /* tslint:disable */

export class ExternalObject<T> {
readonly '': {
readonly '': unique symbol
[K: symbol]: T
}
export interface AvifConfig {
/** 0-100 scale, 100 is lossless */
quality?: number | undefined | null
/** 0-100 scale */
alphaQuality?: number | undefined | null
/** rav1e preset 1 (slow) 10 (fast but crappy), default is 4 */
speed?: number | undefined | null
/** How many threads should be used (0 = match core count) */
threads?: number | undefined | null
/** set to '4:2:0' to use chroma subsampling, default '4:4:4' */
chromaSubsampling?: ChromaSubsampling | undefined | null
}
/**
* https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling
* https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts
*/
export const enum ChromaSubsampling {
/**
* Each of the three Y'CbCr components has the same sample rate, thus there is no chroma subsampling. This scheme is sometimes used in high-end film scanners and cinematic post-production.
* Note that "4:4:4" may instead be wrongly referring to R'G'B' color space, which implicitly also does not have any chroma subsampling (except in JPEG R'G'B' can be subsampled).
* Formats such as HDCAM SR can record 4:4:4 R'G'B' over dual-link HD-SDI.
*/
Yuv444 = 0,
/**
* The two chroma components are sampled at half the horizontal sample rate of luma: the horizontal chroma resolution is halved. This reduces the bandwidth of an uncompressed video signal by one-third.
* Many high-end digital video formats and interfaces use this scheme:
* - [AVC-Intra 100](https://en.wikipedia.org/wiki/AVC-Intra)
* - [Digital Betacam](https://en.wikipedia.org/wiki/Betacam#Digital_Betacam)
* - [Betacam SX](https://en.wikipedia.org/wiki/Betacam#Betacam_SX)
* - [DVCPRO50](https://en.wikipedia.org/wiki/DV#DVCPRO) and [DVCPRO HD](https://en.wikipedia.org/wiki/DV#DVCPRO_HD)
* - [Digital-S](https://en.wikipedia.org/wiki/Digital-S)
* - [CCIR 601](https://en.wikipedia.org/wiki/Rec._601) / [Serial Digital Interface](https://en.wikipedia.org/wiki/Serial_digital_interface) / [D1](https://en.wikipedia.org/wiki/D-1_(Sony))
* - [ProRes (HQ, 422, LT, and Proxy)](https://en.wikipedia.org/wiki/Apple_ProRes)
* - [XDCAM HD422](https://en.wikipedia.org/wiki/XDCAM)
* - [Canon MXF HD422](https://en.wikipedia.org/wiki/Canon_XF-300)
*/
Yuv422 = 1,
/**
* n 4:2:0, the horizontal sampling is doubled compared to 4:1:1,
* but as the **Cb** and **Cr** channels are only sampled on each alternate line in this scheme, the vertical resolution is halved.
* The data rate is thus the same.
* This fits reasonably well with the PAL color encoding system, since this has only half the vertical chrominance resolution of [NTSC](https://en.wikipedia.org/wiki/NTSC).
* It would also fit extremely well with the [SECAM](https://en.wikipedia.org/wiki/SECAM) color encoding system,
* since like that format, 4:2:0 only stores and transmits one color channel per line (the other channel being recovered from the previous line).
* However, little equipment has actually been produced that outputs a SECAM analogue video signal.
* In general, SECAM territories either have to use a PAL-capable display or a [transcoder](https://en.wikipedia.org/wiki/Transcoding) to convert the PAL signal to SECAM for display.
*/
Yuv420 = 2,
/**
* What if the chroma subsampling model is 4:0:0?
* That says to use every pixel of luma data, but that each row has 0 chroma samples applied to it. The resulting image, then, is comprised solely of the luminance data—a greyscale image.
*/
Yuv400 = 3
}
export interface JpegCompressOptions {
/** Output quality, default is 100 (lossless) */
quality?: number | undefined | null
/**
* If true, it will use MozJPEG’s scan optimization. Makes progressive image files smaller.
* Default is `true`
*/
optimizeScans?: boolean | undefined | null
}
export function compressJpegSync(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
export function compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
export const enum CompressionType {
/** Default compression level */
Default = 0,
/** Fast, minimal compression */
Fast = 1,
/** High compression level */
Best = 2,
/** Huffman coding compression */
Huffman = 3,
/** Run-length encoding compression */
Rle = 4
}
export const enum FilterType {
/**
* No processing done, best used for low bit depth greyscale or data with a
* low color count
*/
NoFilter = 0,
/** Filters based on previous pixel in the same scanline */
Sub = 1,
/** Filters based on the scanline above */
Up = 2,
/** Filters based on the average of left and right neighbor pixels */
Avg = 3,
/** Algorithm that takes into account the left, upper left, and above pixels */
Paeth = 4,
/**
* Uses a heuristic to select one of the preceding filters for each
* scanline rather than one filter for the entire image
*/
Adaptive = 5
}
export interface PngEncodeOptions {
/** Default is `CompressionType::Default` */
compressionType?: CompressionType | undefined | null
/** Default is `FilterType::NoFilter` */
filterType?: FilterType | undefined | null
}
export interface PNGLosslessOptions {

@@ -57,12 +154,236 @@ /**

}
export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
export interface JpegCompressOptions {
/** Output quality, default is 100 (lossless) */
quality?: number | undefined | null
export function losslessCompressPngSync(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
export interface PngQuantOptions {
/** default is 70 */
minQuality?: number | undefined | null
/** default is 99 */
maxQuality?: number | undefined | null
/**
* If true, it will use MozJPEG’s scan optimization. Makes progressive image files smaller.
* Default is `true`
* 1- 10
* Faster speeds generate images of lower quality, but may be useful for real-time generation of images.
* default: 5
*/
optimizeScans?: boolean | undefined | null
speed?: number | undefined | null
/**
* Number of least significant bits to ignore.
* Useful for generating palettes for VGA, 15-bit textures, or other retro platforms.
*/
posterization?: number | undefined | null
}
export function compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
export function pngQuantizeSync(input: Buffer, options?: PngQuantOptions | undefined | null): Buffer
export function pngQuantize(input: Buffer, options?: PngQuantOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
export const enum Orientation {
/** Normal */
Horizontal = 1,
MirrorHorizontal = 2,
Rotate180 = 3,
MirrorVertical = 4,
MirrorHorizontalAndRotate270Cw = 5,
Rotate90Cw = 6,
MirrorHorizontalAndRotate90Cw = 7,
Rotate270Cw = 8
}
/**
* Available Sampling Filters.
*
* ## Examples
*
* To test the different sampling filters on a real example, you can find two
* examples called
* [`scaledown`](https://github.com/image-rs/image/tree/master/examples/scaledown)
* and
* [`scaleup`](https://github.com/image-rs/image/tree/master/examples/scaleup)
* in the `examples` directory of the crate source code.
*
* Here is a 3.58 MiB
* [test image](https://github.com/image-rs/image/blob/master/examples/scaledown/test.jpg)
* that has been scaled down to 300x225 px:
*
* <!-- NOTE: To test new test images locally, replace the GitHub path with `../../../docs/` -->
* <div style="display: flex; flex-wrap: wrap; align-items: flex-start;">
* <div style="margin: 0 8px 8px 0;">
* <img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-near.png" title="Nearest"><br>
* Nearest Neighbor
* </div>
* <div style="margin: 0 8px 8px 0;">
* <img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-tri.png" title="Triangle"><br>
* Linear: Triangle
* </div>
* <div style="margin: 0 8px 8px 0;">
* <img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-cmr.png" title="CatmullRom"><br>
* Cubic: Catmull-Rom
* </div>
* <div style="margin: 0 8px 8px 0;">
* <img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-gauss.png" title="Gaussian"><br>
* Gaussian
* </div>
* <div style="margin: 0 8px 8px 0;">
* <img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-lcz2.png" title="Lanczos3"><br>
* Lanczos with window 3
* </div>
* </div>
*
* ## Speed
*
* Time required to create each of the examples above, tested on an Intel
* i7-4770 CPU with Rust 1.37 in release mode:
*
* <table style="width: auto;">
* <tr>
* <th>Nearest</th>
* <td>31 ms</td>
* </tr>
* <tr>
* <th>Triangle</th>
* <td>414 ms</td>
* </tr>
* <tr>
* <th>CatmullRom</th>
* <td>817 ms</td>
* </tr>
* <tr>
* <th>Gaussian</th>
* <td>1180 ms</td>
* </tr>
* <tr>
* <th>Lanczos3</th>
* <td>1170 ms</td>
* </tr>
* </table>
*/
export const enum ResizeFilterType {
/** Nearest Neighbor */
Nearest = 0,
/** Linear Filter */
Triangle = 1,
/** Cubic Filter */
CatmullRom = 2,
/** Gaussian Filter */
Gaussian = 3,
/** Lanczos with window 3 */
Lanczos3 = 4
}
export const enum JsColorType {
/** Pixel is 8-bit luminance */
L8 = 0,
/** Pixel is 8-bit luminance with an alpha channel */
La8 = 1,
/** Pixel contains 8-bit R, G and B channels */
Rgb8 = 2,
/** Pixel is 8-bit RGB with an alpha channel */
Rgba8 = 3,
/** Pixel is 16-bit luminance */
L16 = 4,
/** Pixel is 16-bit luminance with an alpha channel */
La16 = 5,
/** Pixel is 16-bit RGB */
Rgb16 = 6,
/** Pixel is 16-bit RGBA */
Rgba16 = 7,
/** Pixel is 32-bit float RGB */
Rgb32F = 8,
/** Pixel is 32-bit float RGBA */
Rgba32F = 9
}
export interface Metadata {
width: number
height: number
exif?: Record<string, string> | undefined | null
orientation?: number | undefined | null
format: string
colorType: JsColorType
}
export class Transformer {
constructor(input: Buffer)
static fromRgbaPixels(input: Buffer | Uint8ClampedArray, width: number, height: number): Transformer
metadata(withExif?: boolean | undefined | null, signal?: AbortSignal | undefined | null): Promise<Metadata>
/**
* Rotate with exif orientation
* If the orientation param is not null,
* the new orientation value will override the exif orientation value
*/
rotate(orientation?: Orientation | undefined | null): this
/**
* Return a grayscale version of this image.
* Returns `Luma` images in most cases. However, for `f32` images,
* this will return a greyscale `Rgb/Rgba` image instead.
*/
grayscale(): this
/** Invert the colors of this image. */
invert(): this
/**
* Resize this image using the specified filter algorithm.
* The image is scaled to the maximum possible size that fits
* within the bounds specified by `width` and `height`.
*/
resize(width: number, height?: number | undefined | null, filterType?: ResizeFilterType | undefined | null): this
/**
* Performs a Gaussian blur on this image.
* `sigma` is a measure of how much to blur by.
*/
blur(sigma: number): this
/**
* Performs an unsharpen mask on this image.
* `sigma` is the amount to blur the image by.
* `threshold` is a control of how much to sharpen.
*
* See <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
*/
unsharpen(sigma: number, threshold: number): this
/** Filters this image with the specified 3x3 kernel. */
filter3x3(kernel: Array<number>): this
/**
* Adjust the contrast of this image.
* `contrast` is the amount to adjust the contrast by.
* Negative values decrease the contrast and positive values increase the contrast.
*/
adjustContrast(contrast: number): this
/**
* Brighten the pixels of this image.
* `value` is the amount to brighten each pixel by.
* Negative values decrease the brightness and positive values increase it.
*/
brighten(brightness: number): this
/**
* Hue rotate the supplied image.
* `value` is the degrees to rotate each pixel by.
* 0 and 360 do nothing, the rest rotates by the given degree value.
* just like the css webkit filter hue-rotate(180)
*/
huerotate(hue: number): this
/**
* The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression.
* The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size.
* https://developers.google.com/speed/webp/docs/api#simple_encoding_api
*/
webp(qualityFactor?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
/**
* The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression.
* The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size.
* https://developers.google.com/speed/webp/docs/api#simple_encoding_api
*/
webpSync(qualityFactor?: number | undefined | null): Buffer
webpLossless(signal?: AbortSignal | undefined | null): Promise<Buffer>
webpLosslessSync(): Buffer
avif(options?: AvifConfig | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
avifSync(options?: AvifConfig | undefined | null): Buffer
png(options?: PngEncodeOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
pngSync(options?: PngEncodeOptions | undefined | null): Buffer
/** default `quality` is 90 */
jpeg(quality?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
/** default `quality` is 90 */
jpegSync(quality?: number | undefined | null): Buffer
bmp(signal?: AbortSignal | undefined | null): Promise<Buffer>
bmpSync(): Buffer
ico(signal?: AbortSignal | undefined | null): Promise<Buffer>
icoSync(): Buffer
tiff(signal?: AbortSignal | undefined | null): Promise<Buffer>
tiffSync(): Buffer
pnm(signal?: AbortSignal | undefined | null): Promise<Buffer>
pnmSync(): Buffer
tga(signal?: AbortSignal | undefined | null): Promise<Buffer>
tgaSync(): Buffer
farbfeld(signal?: AbortSignal | undefined | null): Promise<Buffer>
farbfeldSync(): Buffer
}

94

index.js

@@ -16,7 +16,7 @@ const { existsSync, readFileSync } = require('fs')

} catch (e) {
return false
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !Boolean(glibcVersionRuntime)
return !glibcVersionRuntime
}

@@ -27,15 +27,30 @@ }

case 'android':
if (arch !== 'arm64') {
throw new Error(`Unsupported architecture on Android ${arch}`)
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'image.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./image.android-arm64.node')
} else {
nativeBinding = require('@napi-rs/image-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'image.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./image.android-arm-eabi.node')
} else {
nativeBinding = require('@napi-rs/image-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'image.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./image.android-arm64.node')
} else {
nativeBinding = require('@napi-rs/image-android-arm64')
}
} catch (e) {
loadError = e
}
break

@@ -45,3 +60,5 @@ case 'win32':

case 'x64':
localFileExisted = existsSync(join(__dirname, 'image.win32-x64-msvc.node'))
localFileExisted = existsSync(
join(__dirname, 'image.win32-x64-msvc.node')
)
try {

@@ -58,3 +75,5 @@ if (localFileExisted) {

case 'ia32':
localFileExisted = existsSync(join(__dirname, 'image.win32-ia32-msvc.node'))
localFileExisted = existsSync(
join(__dirname, 'image.win32-ia32-msvc.node')
)
try {

@@ -71,3 +90,5 @@ if (localFileExisted) {

case 'arm64':
localFileExisted = existsSync(join(__dirname, 'image.win32-arm64-msvc.node'))
localFileExisted = existsSync(
join(__dirname, 'image.win32-arm64-msvc.node')
)
try {

@@ -102,3 +123,5 @@ if (localFileExisted) {

case 'arm64':
localFileExisted = existsSync(join(__dirname, 'image.darwin-arm64.node'))
localFileExisted = existsSync(
join(__dirname, 'image.darwin-arm64.node')
)
try {

@@ -137,3 +160,5 @@ if (localFileExisted) {

if (isMusl()) {
localFileExisted = existsSync(join(__dirname, 'image.linux-x64-musl.node'))
localFileExisted = existsSync(
join(__dirname, 'image.linux-x64-musl.node')
)
try {

@@ -149,3 +174,5 @@ if (localFileExisted) {

} else {
localFileExisted = existsSync(join(__dirname, 'image.linux-x64-gnu.node'))
localFileExisted = existsSync(
join(__dirname, 'image.linux-x64-gnu.node')
)
try {

@@ -164,3 +191,5 @@ if (localFileExisted) {

if (isMusl()) {
localFileExisted = existsSync(join(__dirname, 'image.linux-arm64-musl.node'))
localFileExisted = existsSync(
join(__dirname, 'image.linux-arm64-musl.node')
)
try {

@@ -176,3 +205,5 @@ if (localFileExisted) {

} else {
localFileExisted = existsSync(join(__dirname, 'image.linux-arm64-gnu.node'))
localFileExisted = existsSync(
join(__dirname, 'image.linux-arm64-gnu.node')
)
try {

@@ -190,3 +221,5 @@ if (localFileExisted) {

case 'arm':
localFileExisted = existsSync(join(__dirname, 'image.linux-arm-gnueabihf.node'))
localFileExisted = existsSync(
join(__dirname, 'image.linux-arm-gnueabihf.node')
)
try {

@@ -217,5 +250,16 @@ if (localFileExisted) {

const { losslessCompressPng, compressJpeg } = nativeBinding
const { ChromaSubsampling, compressJpegSync, compressJpeg, CompressionType, FilterType, losslessCompressPngSync, losslessCompressPng, pngQuantizeSync, pngQuantize, Orientation, ResizeFilterType, JsColorType, Transformer } = nativeBinding
module.exports.ChromaSubsampling = ChromaSubsampling
module.exports.compressJpegSync = compressJpegSync
module.exports.compressJpeg = compressJpeg
module.exports.CompressionType = CompressionType
module.exports.FilterType = FilterType
module.exports.losslessCompressPngSync = losslessCompressPngSync
module.exports.losslessCompressPng = losslessCompressPng
module.exports.compressJpeg = compressJpeg
module.exports.pngQuantizeSync = pngQuantizeSync
module.exports.pngQuantize = pngQuantize
module.exports.Orientation = Orientation
module.exports.ResizeFilterType = ResizeFilterType
module.exports.JsColorType = JsColorType
module.exports.Transformer = Transformer
{
"name": "@napi-rs/image",
"version": "1.0.0",
"version": "1.1.0",
"main": "index.js",

@@ -20,2 +20,6 @@ "types": "index.d.ts",

],
"files": [
"index.js",
"index.d.ts"
],
"publishConfig": {

@@ -42,18 +46,2 @@ "registry": "https://registry.npmjs.org/",

"license": "MIT",
"devDependencies": {
"@napi-rs/cli": "^2.2.1",
"@types/node": "^17.0.8",
"ava": "^4.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1"
},
"ava": {
"extensions": [
"mjs"
],
"timeout": "3m",
"environmentVariables": {
"NODE_ENV": "ava"
}
},
"engines": {

@@ -67,3 +55,3 @@ "node": ">= 10"

"scripts": {
"artifacts": "napi artifacts",
"artifacts": "napi artifacts -d ../../artifacts",
"build": "napi build --platform --release",

@@ -75,27 +63,20 @@ "build:debug": "napi build --platform",

"prepublishOnly": "napi prepublish -t npm",
"test": "ava",
"version": "napi version"
},
"prettier": {
"printWidth": 120,
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"arrowParens": "always"
},
"repository": "git@github.com:Brooooooklyn/imgquant.git",
"repository": "git@github.com:Brooooooklyn/Image.git",
"gitHead": "0aa7effa90873c50d9cd418b873fde5b07d670d6",
"optionalDependencies": {
"@napi-rs/image-win32-x64-msvc": "1.0.0",
"@napi-rs/image-darwin-x64": "1.0.0",
"@napi-rs/image-linux-x64-gnu": "1.0.0",
"@napi-rs/image-darwin-arm64": "1.0.0",
"@napi-rs/image-android-arm64": "1.0.0",
"@napi-rs/image-linux-arm64-gnu": "1.0.0",
"@napi-rs/image-linux-arm64-musl": "1.0.0",
"@napi-rs/image-linux-arm-gnueabihf": "1.0.0",
"@napi-rs/image-linux-x64-musl": "1.0.0",
"@napi-rs/image-freebsd-x64": "1.0.0",
"@napi-rs/image-win32-ia32-msvc": "1.0.0",
"@napi-rs/image-android-arm-eabi": "1.0.0"
"@napi-rs/image-win32-x64-msvc": "1.1.0",
"@napi-rs/image-darwin-x64": "1.1.0",
"@napi-rs/image-linux-x64-gnu": "1.1.0",
"@napi-rs/image-darwin-arm64": "1.1.0",
"@napi-rs/image-android-arm64": "1.1.0",
"@napi-rs/image-linux-arm64-gnu": "1.1.0",
"@napi-rs/image-linux-arm64-musl": "1.1.0",
"@napi-rs/image-linux-arm-gnueabihf": "1.1.0",
"@napi-rs/image-linux-x64-musl": "1.1.0",
"@napi-rs/image-freebsd-x64": "1.1.0",
"@napi-rs/image-win32-ia32-msvc": "1.1.0",
"@napi-rs/image-android-arm-eabi": "1.1.0"
}
}
# `@napi-rs/image`
Image processing library.
Transform and optimize images library.
![CI](https://github.com/Brooooooklyn/image/workflows/CI/badge.svg)
See [Examples](../../example.mjs) for usage.
[![install size](https://packagephobia.com/badge?p=@napi-rs/image)](https://packagephobia.com/result?p=@napi-rs/image)
[![Downloads](https://img.shields.io/npm/dm/@napi-rs/image.svg?sanitize=true)](https://npmcharts.com/compare/@napi-rs/image?minimal=true)
## Support matrix
## Transformer:
| | node10 | node12 | node14 | node16 | node17 |
| --------------------- | ------ | ------ | ------ | ------ | ------ |
| Windows x64 | ✓ | ✓ | ✓ | ✓ | ✓ |
| Windows x32 | ✓ | ✓ | ✓ | ✓ | ✓ |
| macOS x64 | ✓ | ✓ | ✓ | ✓ | ✓ |
| macOS arm64 (m chips) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Linux x64 gnu | ✓ | ✓ | ✓ | ✓ | ✓ |
| Linux x64 musl | ✓ | ✓ | ✓ | ✓ | ✓ |
| Linux arm gnu | ✓ | ✓ | ✓ | ✓ | ✓ |
| Linux arm64 gnu | ✓ | ✓ | ✓ | ✓ | ✓ |
| Linux arm64 musl | ✓ | ✓ | ✓ | ✓ | ✓ |
| Android arm64 | ✓ | ✓ | ✓ | ✓ | ✓ |
| Android armv7 | ✓ | ✓ | ✓ | ✓ | ✓ |
| FreeBSD x64 | ✓ | ✓ | ✓ | ✓ | ✓ |
This library support encode/decode these formats:
## Lossless compression
| Format | Input | Output |
| --------- | ----------------------------------------- | --------------------------------------- |
| RawPixels | RGBA 8 bits pixels | |
| JPEG | Baseline and progressive | Baseline JPEG |
| PNG | All supported color types | Same as decoding |
| BMP | ✅ | Rgb8, Rgba8, Gray8, GrayA8 |
| ICO | ✅ | ✅ |
| TIFF | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 |
| WebP | No | ✅ |
| AVIF | No | ✅ |
| PNM | PBM, PGM, PPM, standard PAM | ✅ |
| DDS | DXT1, DXT3, DXT5 | No |
| TGA | ✅ | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 |
| OpenEXR | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) |
| farbfeld | ✅ | ✅ |
### `PNG`
See [index.d.ts](./index.d.ts) for API reference.
### New from Constructor
```ts
import { Transformer } from '@napi-rs/image'
const transformer = new Transformer(input)
```
### New from RGBA RawPixels
```ts
import { Transformer } from '@napi-rs/image'
import { decode } from 'blurhash'
// Uint8ClampedArray
const pixels = decode('LEHV6nWB2yk8pyo0adR*.7kCMdnj', 32, 32)
const transformer = Transformer.fromRgbaPixels(pixels, 32, 32)
```
### Metadata
```ts
metadata(withExif?: boolean | undefined | null, signal?: AbortSignal | undefined | null): Promise<Metadata>
export interface Metadata {
width: number
height: number
exif?: Record<string, string> | undefined | null
orientation?: number | undefined | null
format: string
colorType: JsColorType
}
export const enum JsColorType {
/** Pixel is 8-bit luminance */
L8 = 0,
/** Pixel is 8-bit luminance with an alpha channel */
La8 = 1,
/** Pixel contains 8-bit R, G and B channels */
Rgb8 = 2,
/** Pixel is 8-bit RGB with an alpha channel */
Rgba8 = 3,
/** Pixel is 16-bit luminance */
L16 = 4,
/** Pixel is 16-bit luminance with an alpha channel */
La16 = 5,
/** Pixel is 16-bit RGB */
Rgb16 = 6,
/** Pixel is 16-bit RGBA */
Rgba16 = 7,
/** Pixel is 32-bit float RGB */
Rgb32F = 8,
/** Pixel is 32-bit float RGBA */
Rgba32F = 9
}
```
**Example**:
```ts
import { promises as fs } from 'fs'
import { Transformer } from '@napi-rs/image'
const WITH_EXIF_JPG = await fs.readFile('with-exif.jpg')
const decoder = new Transformer(WITH_EXIF_JPG)
const metadata = await decoder.metadata(true)
```
The metadata will be
```js
{
colorType: 2,
exif: {
Orientation: 'Unknown (5)',
'Resolution Unit': 'in',
'This image has an Exif SubIFD': '90',
'X Resolution': '72 pixels per in',
'Y Resolution': '72 pixels per in',
},
format: 'jpeg',
height: 450,
orientation: 5,
width: 600,
}
```
### Transform Image format
```ts
import { promises as fs } from 'fs'
import { Transformer } from '@napi-rs/image'
const PNG = await fs.readFile('./un-optimized.png')
const webp = await new Transformer(PNG).webp()
await fs.writeFile('optimized.webp)
```
#### webp
> The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression.
>
> The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size.
>
> https://developers.google.com/speed/webp/docs/api#simple_encoding_api
>
> Default is 90
```ts
webp(qualityFactor: number, signal?: AbortSignal | undefined | null): Promise<Buffer>
webpSync(qualityFactor: number): Buffer
/// Encode lossless webp image
webpLossless(signal?: AbortSignal | undefined | null): Promise<Buffer>
webpLosslessSync(): Buffer
```
#### AVIF
**Config**:
```ts
export interface AvifConfig {
/** 0-100 scale 100 is lossless */
quality?: number | undefined | null
/** 0-100 scale */
alphaQuality?: number | undefined | null
/** rav1e preset 1 (slow) 10 (fast but crappy), default is 4 */
speed?: number | undefined | null
/** How many threads should be used (0 = match core count) */
threads?: number | undefined | null
/** set to '4:2:0' to use chroma subsampling, default '4:4:4' */
chromaSubsampling?: ChromaSubsampling | undefined | null
}
/**
* https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling
* https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts
*/
export const enum ChromaSubsampling {
/**
* Each of the three Y'CbCr components has the same sample rate, thus there is no chroma subsampling. This scheme is sometimes used in high-end film scanners and cinematic post-production.
* Note that "4:4:4" may instead be wrongly referring to R'G'B' color space, which implicitly also does not have any chroma subsampling (except in JPEG R'G'B' can be subsampled).
* Formats such as HDCAM SR can record 4:4:4 R'G'B' over dual-link HD-SDI.
*/
Yuv444 = 0,
/**
* The two chroma components are sampled at half the horizontal sample rate of luma: the horizontal chroma resolution is halved. This reduces the bandwidth of an uncompressed video signal by one-third.
* Many high-end digital video formats and interfaces use this scheme:
* - [AVC-Intra 100](https://en.wikipedia.org/wiki/AVC-Intra)
* - [Digital Betacam](https://en.wikipedia.org/wiki/Betacam#Digital_Betacam)
* - [Betacam SX](https://en.wikipedia.org/wiki/Betacam#Betacam_SX)
* - [DVCPRO50](https://en.wikipedia.org/wiki/DV#DVCPRO) and [DVCPRO HD](https://en.wikipedia.org/wiki/DV#DVCPRO_HD)
* - [Digital-S](https://en.wikipedia.org/wiki/Digital-S)
* - [CCIR 601](https://en.wikipedia.org/wiki/Rec._601) / [Serial Digital Interface](https://en.wikipedia.org/wiki/Serial_digital_interface) / [D1](https://en.wikipedia.org/wiki/D-1_(Sony))
* - [ProRes (HQ, 422, LT, and Proxy)](https://en.wikipedia.org/wiki/Apple_ProRes)
* - [XDCAM HD422](https://en.wikipedia.org/wiki/XDCAM)
* - [Canon MXF HD422](https://en.wikipedia.org/wiki/Canon_XF-300)
*/
Yuv422 = 1,
/**
* n 4:2:0, the horizontal sampling is doubled compared to 4:1:1,
* but as the **Cb** and **Cr** channels are only sampled on each alternate line in this scheme, the vertical resolution is halved.
* The data rate is thus the same.
* This fits reasonably well with the PAL color encoding system, since this has only half the vertical chrominance resolution of [NTSC](https://en.wikipedia.org/wiki/NTSC).
* It would also fit extremely well with the [SECAM](https://en.wikipedia.org/wiki/SECAM) color encoding system,
* since like that format, 4:2:0 only stores and transmits one color channel per line (the other channel being recovered from the previous line).
* However, little equipment has actually been produced that outputs a SECAM analogue video signal.
* In general, SECAM territories either have to use a PAL-capable display or a [transcoder](https://en.wikipedia.org/wiki/Transcoding) to convert the PAL signal to SECAM for display.
*/
Yuv420 = 2,
/**
* What if the chroma subsampling model is 4:0:0?
* That says to use every pixel of luma data, but that each row has 0 chroma samples applied to it. The resulting image, then, is comprised solely of the luminance data—a greyscale image.
*/
Yuv400 = 3,
}
```
```ts
avif(options?: AvifConfig | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
avifSync(options?: AvifConfig | undefined | null): Buffer
```
#### PNG
**PngEncodeOptions**:
```ts
export interface PngEncodeOptions {
/** Default is `CompressionType::Default` */
compressionType?: CompressionType | undefined | null
/** Default is `FilterType::NoFilter` */
filterType?: FilterType | undefined | null
}
export const enum CompressionType {
/** Default compression level */
Default = 0,
/** Fast, minimal compression */
Fast = 1,
/** High compression level */
Best = 2,
/** Huffman coding compression */
Huffman = 3,
/** Run-length encoding compression */
Rle = 4,
}
export const enum FilterType {
/**
* No processing done, best used for low bit depth greyscale or data with a
* low color count
*/
NoFilter = 0,
/** Filters based on previous pixel in the same scanline */
Sub = 1,
/** Filters based on the scanline above */
Up = 2,
/** Filters based on the average of left and right neighbor pixels */
Avg = 3,
/** Algorithm that takes into account the left, upper left, and above pixels */
Paeth = 4,
/**
* Uses a heuristic to select one of the preceding filters for each
* scanline rather than one filter for the entire image
*/
Adaptive = 5,
}
```
```ts
png(options?: PngEncodeOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
pngSync(options?: PngEncodeOptions | undefined | null): Buffer
```
#### JPEG
```ts
/** default `quality` is 90 */
jpeg(quality?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise<Buffer>
/** default `quality` is 90 */
jpegSync(quality?: number | undefined | null): Buffer
```
#### BMP
```ts
bmp(signal?: AbortSignal | undefined | null): Promise<Buffer>
bmpSync(): Buffer
```
#### ICO
```ts
ico(signal?: AbortSignal | undefined | null): Promise<Buffer>
icoSync(): Buffer
```
#### TIFF
```ts
tiff(signal?: AbortSignal | undefined | null): Promise<Buffer>
tiffSync(): Buffer
```
#### PNM
```ts
pnm(signal?: AbortSignal | undefined | null): Promise<Buffer>
pnmSync(): Buffer
```
#### TGA
```ts
tga(signal?: AbortSignal | undefined | null): Promise<Buffer>
tgaSync(): Buffer
```
#### Farbfeld
```ts
farbfeld(signal?: AbortSignal | undefined | null): Promise<Buffer>
farbfeldSync(): Buffer
```
### Manipulate Image
#### `rotate`
> Rotate the image with exif orientation, if the input image contains no exif information, this API will have no effect.
```ts
/**
* Rotate with exif orientation
* If the orientation param is not null,
* the new orientation value will override the exif orientation value
*/
rotate(): this
```
**Example**:
This image has orientation value `5` in exif:
<img src="../../with-exif.jpg" alt="with-exif.jpg" width="200" />
Without rotate:
```ts
import { promises as fs } from 'fs'
import { Transformer } from '@napi-rs/image'
const WITH_EXIF_JPG = await fs.readFile('with-exif.jpg')
const imageOutputWithoutRotateWebp = await new Transformer(WITH_EXIF).resize(450 / 2).webp(75)
writeFileSync('output-exif.no-rotate.image.webp', imageOutputWithoutRotateWebp)
```
<img src="../../output-exif.no-rotate.image.webp" alt="output-exif.no-rotate.image.webp" width="200" />
With rotate:
```ts
import { promises as fs } from 'fs'
import { Transformer } from '@napi-rs/image'
const WITH_EXIF_JPG = await fs.readFile('with-exif.jpg')
const imageOutputWebp = await new Transformer(WITH_EXIF)
.rotate()
.resize(450 / 2)
.webp(75)
console.timeEnd('@napi-rs/image webp')
writeFileSync('output-exif.image.webp', imageOutputWebp)
```
<img src="../../output-exif.image.webp" alt="output-exif.image.webp" width="200" />
#### `grayscale`
```ts
/**
* Return a grayscale version of this image.
* Returns `Luma` images in most cases. However, for `f32` images,
* this will return a greyscale `Rgb/Rgba` image instead.
*/
grayscale(): this
```
#### `invert`
> Invert the colors of this image.
```ts
invert(): this
```
#### `resize`
```ts
/**
* Resize this image using the specified filter algorithm.
* The image is scaled to the maximum possible size that fits
* within the bounds specified by `width` and `height`.
*/
resize(width: number, height?: number | undefined | null, filterType?: ResizeFilterType | undefined | null): this
export const enum ResizeFilterType {
/** Nearest Neighbor */
Nearest = 0,
/** Linear Filter */
Triangle = 1,
/** Cubic Filter */
CatmullRom = 2,
/** Gaussian Filter */
Gaussian = 3,
/** Lanczos with window 3 */
Lanczos3 = 4
}
```
**ResizeFilterType**:
To test the different sampling filters on a real example, you can find two
examples called
[`scaledown`](https://github.com/image-rs/image/tree/master/examples/scaledown)
and
[`scaleup`](https://github.com/image-rs/image/tree/master/examples/scaleup)
in the `examples` directory of the crate source code.
Here is a 3.58 MiB
[test image](https://github.com/image-rs/image/blob/master/examples/scaledown/test.jpg)
that has been scaled down to 300x225 px:
<!-- NOTE: To test new test images locally, replace the GitHub path with `../../../docs/` -->
<div style="display: flex; flex-wrap: wrap; align-items: flex-start;">
<div style="margin: 0 8px 8px 0;">
<img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-near.png" title="Nearest"><br>
Nearest Neighbor
</div>
<div style="margin: 0 8px 8px 0;">
<img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-tri.png" title="Triangle"><br>
Linear: Triangle
</div>
<div style="margin: 0 8px 8px 0;">
<img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-cmr.png" title="CatmullRom"><br>
Cubic: Catmull-Rom
</div>
<div style="margin: 0 8px 8px 0;">
<img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-gauss.png" title="Gaussian"><br>
Gaussian
</div>
<div style="margin: 0 8px 8px 0;">
<img src="https://raw.githubusercontent.com/image-rs/image/master/examples/scaledown/scaledown-test-lcz2.png" title="Lanczos3"><br>
Lanczos with window 3
</div>
</div>
**Speed**
Time required to create each of the examples above, tested on an Intel
i7-4770 CPU with Rust 1.37 in release mode:
<table style="width: auto;">
<tr>
<th>Nearest</th>
<td>31 ms</td>
</tr>
<tr>
<th>Triangle</th>
<td>414 ms</td>
</tr>
<tr>
<th>CatmullRom</th>
<td>817 ms</td>
</tr>
<tr>
<th>Gaussian</th>
<td>1180 ms</td>
</tr>
<tr>
<th>Lanczos3</th>
<td>1170 ms</td>
</tr>
</table>
#### `blur`
> Performs a Gaussian blur on this image. <br/>
> sigma` is a measure of how much to blur by.
```ts
blur(sigma: number): this
```
#### `unsharpen`
> Performs an unsharpen mask on this image. <br/> > `sigma` is the amount to blur the image by. <br/> > `threshold` is a control of how much to sharpen.
>
> See <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
```ts
unsharpen(sigma: number, threshold: number): this
```
#### `filter3x3`
Filters this image with the specified 3x3 kernel. Error will thrown if the kernel length is not `9`.
```ts
filter3x3(kernel: Array<number>): this
```
#### `adjustContrast`
> Adjust the contrast of this image.<br/> > `contrast` is the amount to adjust the contrast by.<br/>
> Negative values decrease the contrast and positive values increase the contrast.
```ts
adjustContrast(contrast: number): this
```
#### `brighten`
> Brighten the pixels of this image.<br/> > `value` is the amount to brighten each pixel by. <br/>
> Negative values decrease the brightness and positive values increase it.
```ts
brighten(brightness: number): this
```
#### `huerotate`
> Hue rotate the supplied image.<br/> > `value` is the degrees to rotate each pixel by.
> 0 and 360 do nothing, the rest rotates by the given degree value.
> just like the css webkit filter hue-rotate(180)
```ts
huerotate(hue: number): this
```
## Optimize PNG
### Lossless compression
Lossless optimize PNG powered by [oxipng](https://github.com/shssoichiro/oxipng).
**PNGLosslessOptions**
```ts
export interface PNGLosslessOptions {

@@ -75,8 +595,55 @@ /**

}
export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
```
### `JPEG`
```ts
export function losslessCompressPng(
input: Buffer,
options?: PNGLosslessOptions | undefined | null,
signal?: AbortSignal | undefined | null,
): Promise<Buffer>
export function losslessCompressPngSync(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
```
### Lossy compression
Powered by [pngquant](https://github.com/ImageOptim/libimagequant), converts RGBA images to palette-based 8-bit indexed images, _including_ alpha component.
**PngQuantOptions**:
```ts
export interface PngQuantOptions {
/** default is 70 */
minQuality?: number | undefined | null
/** default is 99 */
maxQuality?: number | undefined | null
/**
* 1- 10
* Faster speeds generate images of lower quality, but may be useful for real-time generation of images.
* default: 5
*/
speed?: number | undefined | null
/**
* Number of least significant bits to ignore.
* Useful for generating palettes for VGA, 15-bit textures, or other retro platforms.
*/
posterization?: number | undefined | null
}
```
```ts
export function pngQuantize(
input: Buffer,
options?: PngQuantOptions | undefined | null,
signal?: AbortSignal | undefined | null,
): Promise<Buffer>
export function pngQuantizeSync(input: Buffer, options?: PngQuantOptions | undefined | null): Buffer
```
## Optimize JPEG
Lossy and Lossless JPEG compression powered by [mozjpeg](https://github.com/mozilla/mozjpeg).
**JpegCompressOptions**:
```ts
export interface JpegCompressOptions {

@@ -91,3 +658,15 @@ /** Output quality, default is 100 (lossless) */

}
export function compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
```
```ts
export function compressJpeg(
input: Buffer,
options?: JpegCompressOptions | undefined | null,
signal?: AbortSignal | undefined | null,
): Promise<Buffer>
export function compressJpegSync(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
```
## Credits
See [Credits](./credits.md)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc