mirror of
https://github.com/Brooooooklyn/Image.git
synced 2025-12-08 18:36:03 +00:00
Init
This commit is contained in:
commit
c0997adba5
9
.cargo/config.toml
Normal file
9
.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
rustflags = ["-C", "target-feature=+sse4.2", "-C", "target-feature=-crt-static"]
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
linker = "aarch64-linux-musl-gcc"
|
||||
rustflags = ["-C", "target-feature=-crt-static"]
|
||||
[target.armv7-unknown-linux-gnueabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
13
.gitattributes
vendored
Normal file
13
.gitattributes
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
|
||||
*.ts text eol=lf merge=union
|
||||
*.tsx text eol=lf merge=union
|
||||
*.rs text eol=lf merge=union
|
||||
*.js text eol=lf merge=union
|
||||
*.json text eol=lf merge=union
|
||||
*.debug text eol=lf merge=union
|
||||
|
||||
index.js linguist-detectable=false
|
||||
index.d.ts inguist-detectable=false
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: [Brooooooklyn]
|
||||
462
.github/workflows/CI.yml
vendored
Normal file
462
.github/workflows/CI.yml
vendored
Normal file
@ -0,0 +1,462 @@
|
||||
name: CI
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
APP_NAME: image
|
||||
MACOSX_DEPLOYMENT_TARGET: '10.13'
|
||||
'on':
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags-ignore:
|
||||
- '**'
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- LICENSE
|
||||
- '**/*.gitignore'
|
||||
- .editorconfig
|
||||
- docs/**
|
||||
pull_request: null
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, 'skip ci')"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
architecture: x64
|
||||
build: |
|
||||
yarn build
|
||||
strip -x *.node
|
||||
- host: windows-latest
|
||||
build: |
|
||||
yarn build
|
||||
target: x86_64-pc-windows-msvc
|
||||
architecture: x64
|
||||
- host: windows-latest
|
||||
build: |
|
||||
yarn build --target i686-pc-windows-msvc
|
||||
yarn test
|
||||
target: i686-pc-windows-msvc
|
||||
architecture: x86
|
||||
- host: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
architecture: x64
|
||||
docker: |
|
||||
docker pull $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-debian
|
||||
docker tag $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-debian builder
|
||||
build: |
|
||||
docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/build -w /build builder yarn build && strip *.node
|
||||
- host: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
architecture: x64
|
||||
docker: |
|
||||
docker pull $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
docker tag $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-alpine builder
|
||||
build: docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/build -w /build builder sh -c "unset RUSTFLAGS && unset CC && yarn build && strip *.node"
|
||||
- host: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
build: |
|
||||
yarn build --target=aarch64-apple-darwin
|
||||
strip -x *.node
|
||||
- host: ubuntu-latest
|
||||
architecture: x64
|
||||
target: aarch64-unknown-linux-gnu
|
||||
setup: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu -y
|
||||
build: |
|
||||
yarn build --target=aarch64-unknown-linux-gnu
|
||||
aarch64-linux-gnu-strip *.node
|
||||
- host: ubuntu-latest
|
||||
architecture: x64
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
setup: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y
|
||||
build: |
|
||||
yarn build --target=armv7-unknown-linux-gnueabihf
|
||||
arm-linux-gnueabihf-strip *.node
|
||||
- host: ubuntu-latest
|
||||
architecture: x64
|
||||
target: aarch64-linux-android
|
||||
build: |
|
||||
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang"
|
||||
export CC="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang"
|
||||
export CXX="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang++"
|
||||
export PATH="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH}"
|
||||
yarn build --target aarch64-linux-android
|
||||
${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip *.node
|
||||
- host: ubuntu-latest
|
||||
architecture: x64
|
||||
target: armv7-linux-androideabi
|
||||
build: |
|
||||
export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang"
|
||||
export CC="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang"
|
||||
export CXX="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang++"
|
||||
export PATH="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH}"
|
||||
yarn build --target armv7-linux-androideabi
|
||||
${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-strip *.node
|
||||
- host: ubuntu-latest
|
||||
architecture: x64
|
||||
target: aarch64-unknown-linux-musl
|
||||
downloadTarget: aarch64-unknown-linux-musl
|
||||
docker: |
|
||||
docker pull ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
docker tag ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine builder
|
||||
build: |
|
||||
docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd):/build -w /build builder sh -c "yarn build --target=aarch64-unknown-linux-musl && /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node"
|
||||
name: stable - ${{ matrix.settings.target }} - node@16
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
check-latest: true
|
||||
cache: yarn
|
||||
architecture: ${{ matrix.settings.architecture }}
|
||||
- name: Setup nasm
|
||||
uses: ilammy/setup-nasm@v1
|
||||
if: matrix.settings.target == 'x86_64-pc-windows-msvc' || matrix.settings.target == 'x86_64-apple-darwin'
|
||||
- name: Install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
override: true
|
||||
toolchain: stable
|
||||
target: ${{ matrix.settings.target }}
|
||||
- name: Generate Cargo.lock
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: generate-lockfile
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ matrix.settings.target }}-node@16-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Cache cargo index
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ matrix.settings.target }}-node@16-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-${{ matrix.settings.target }}-node@16-${{ hashFiles('yarn.lock') }}
|
||||
- name: Pull latest image
|
||||
run: ${{ matrix.settings.docker }}
|
||||
env:
|
||||
DOCKER_REGISTRY_URL: ghcr.io
|
||||
if: ${{ matrix.settings.docker }}
|
||||
- name: Setup toolchain
|
||||
run: ${{ matrix.settings.setup }}
|
||||
if: ${{ matrix.settings.setup }}
|
||||
shell: bash
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Build
|
||||
run: ${{ matrix.settings.build }}
|
||||
shell: bash
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: bindings-${{ matrix.settings.target }}
|
||||
path: ${{ env.APP_NAME }}.*.node
|
||||
if-no-files-found: error
|
||||
build-freebsd:
|
||||
runs-on: macos-10.15
|
||||
name: Build FreeBSD
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
id: build
|
||||
uses: vmactions/freebsd-vm@v0.1.5
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
RUSTUP_HOME: /usr/local/rustup
|
||||
CARGO_HOME: /usr/local/cargo
|
||||
RUSTUP_IO_THREADS: 1
|
||||
with:
|
||||
envs: DEBUG RUSTUP_HOME CARGO_HOME RUSTUP_IO_THREADS
|
||||
usesh: true
|
||||
mem: 3000
|
||||
prepare: |
|
||||
pkg install -y curl node14 python2
|
||||
curl -qL https://www.npmjs.com/install.sh | sh
|
||||
npm install -g yarn
|
||||
curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
sh rustup.sh -y --profile minimal --default-toolchain stable
|
||||
export PATH="/usr/local/cargo/bin:$PATH"
|
||||
echo "~~~~ rustc --version ~~~~"
|
||||
rustc --version
|
||||
echo "~~~~ node -v ~~~~"
|
||||
node -v
|
||||
echo "~~~~ yarn --version ~~~~"
|
||||
yarn --version
|
||||
run: |
|
||||
export PATH="/usr/local/cargo/bin:$PATH"
|
||||
pwd
|
||||
ls -lah
|
||||
whoami
|
||||
env
|
||||
freebsd-version
|
||||
yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
yarn build
|
||||
strip -x *.node
|
||||
yarn test
|
||||
rm -rf node_modules
|
||||
rm -rf target
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: bindings-freebsd
|
||||
path: ${{ env.APP_NAME }}.*.node
|
||||
if-no-files-found: error
|
||||
test-macOS-windows-binding:
|
||||
name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
settings:
|
||||
- host: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
node:
|
||||
- '14'
|
||||
- '16'
|
||||
- '17'
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
check-latest: true
|
||||
cache: yarn
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-test-${{ matrix.settings.target }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: bindings-${{ matrix.settings.target }}
|
||||
path: .
|
||||
- name: List packages
|
||||
run: ls -R .
|
||||
shell: bash
|
||||
- name: Test bindings
|
||||
run: yarn test
|
||||
test-linux-x64-gnu-binding:
|
||||
name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }}
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- '14'
|
||||
- '16'
|
||||
- '17'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
check-latest: true
|
||||
cache: yarn
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-test-linux-x64-gnu-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: bindings-x86_64-unknown-linux-gnu
|
||||
path: .
|
||||
- name: List packages
|
||||
run: ls -R .
|
||||
shell: bash
|
||||
- name: Test bindings
|
||||
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim yarn test
|
||||
test-linux-x64-musl-binding:
|
||||
name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- '14'
|
||||
- '16'
|
||||
- '17'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
check-latest: true
|
||||
cache: yarn
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-test-x86_64-unknown-linux-musl-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: bindings-x86_64-unknown-linux-musl
|
||||
path: .
|
||||
- name: List packages
|
||||
run: ls -R .
|
||||
shell: bash
|
||||
- name: Test bindings
|
||||
run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine yarn test
|
||||
test-linux-aarch64-gnu-binding:
|
||||
name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- '14'
|
||||
- '16'
|
||||
- '17'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: bindings-aarch64-unknown-linux-gnu
|
||||
path: .
|
||||
- name: List packages
|
||||
run: ls -R .
|
||||
shell: bash
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-test-linux-aarch64-gnu-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --ignore-platform --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Setup and run tests
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: ghcr.io/napi-rs/napi-rs/nodejs:aarch64-${{ matrix.node }}
|
||||
options: '-v ${{ github.workspace }}:/build -w /build'
|
||||
run: |
|
||||
set -e
|
||||
yarn test
|
||||
ls -la
|
||||
test-linux-arm-gnueabihf-binding:
|
||||
name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }}
|
||||
needs:
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- '14'
|
||||
- '16'
|
||||
- '17'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: bindings-armv7-unknown-linux-gnueabihf
|
||||
path: .
|
||||
- name: List packages
|
||||
run: ls -R .
|
||||
shell: bash
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-test-linux-arm-gnueabihf-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --ignore-platform --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Setup and run tests
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: ghcr.io/napi-rs/napi-rs/nodejs:armhf-${{ matrix.node }}
|
||||
options: '-v ${{ github.workspace }}:/build -w /build'
|
||||
run: |
|
||||
set -e
|
||||
yarn test
|
||||
ls -la
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-freebsd
|
||||
- test-macOS-windows-binding
|
||||
- test-linux-x64-gnu-binding
|
||||
- test-linux-x64-musl-binding
|
||||
- test-linux-aarch64-gnu-binding
|
||||
- test-linux-arm-gnueabihf-binding
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
check-latest: true
|
||||
cache: yarn
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: node_modules
|
||||
key: npm-cache-ubuntu-latest-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
npm-cache-
|
||||
- name: Install dependencies
|
||||
run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Move artifacts
|
||||
run: yarn artifacts
|
||||
- name: List packages
|
||||
run: ls -R ./npm
|
||||
shell: bash
|
||||
- name: Publish
|
||||
run: |
|
||||
if git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+$";
|
||||
then
|
||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
||||
npm publish --access public
|
||||
elif git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+";
|
||||
then
|
||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
||||
npm publish --tag next --access public
|
||||
else
|
||||
echo "Not a release, skipping publish"
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
target
|
||||
node_modules
|
||||
*.node
|
||||
Cargo.lock
|
||||
.swc
|
||||
.DS_Store
|
||||
10
.npmignore
Normal file
10
.npmignore
Normal file
@ -0,0 +1,10 @@
|
||||
target
|
||||
Cargo.lock
|
||||
.cargo
|
||||
.github
|
||||
npm
|
||||
.eslintrc
|
||||
.prettierignore
|
||||
rustfmt.toml
|
||||
yarn.lock
|
||||
*.node
|
||||
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
target
|
||||
node_modules
|
||||
lib
|
||||
35
Cargo.toml
Normal file
35
Cargo.toml
Normal file
@ -0,0 +1,35 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "napi-rs_pngquant"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
napi = {version = "2", default-features = false, features = ["napi3"]}
|
||||
napi-derive = {version = "2", default-features = false, features = ["type-def"]}
|
||||
|
||||
[target.'cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))'.dependencies.oxipng]
|
||||
default-features = false
|
||||
features = ["parallel", "libdeflater"]
|
||||
version = "5"
|
||||
|
||||
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))'.dependencies.oxipng]
|
||||
default-features = false
|
||||
features = ["parallel"]
|
||||
version = "5"
|
||||
|
||||
[target.'cfg(not(all(target_os = "linux", target_arch = "arm")))'.dependencies.mozjpeg-sys]
|
||||
version = "1"
|
||||
|
||||
[target.'cfg(all(target_os = "linux", target_arch = "arm"))'.dependencies.mozjpeg-sys]
|
||||
default-features = false
|
||||
version = "1"
|
||||
|
||||
[build-dependencies]
|
||||
napi-build = "1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present LongYinan(github@lyn.one)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
91
README.md
Normal file
91
README.md
Normal file
@ -0,0 +1,91 @@
|
||||
# `@napi-rs/image`
|
||||
|
||||
Image processing library.
|
||||
|
||||

|
||||
[](https://packagephobia.com/result?p=@napi-rs/image)
|
||||
[](https://npmcharts.com/compare/@napi-rs/image?minimal=true)
|
||||
|
||||
## Support matrix
|
||||
|
||||
| | 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 | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
|
||||
## Lossless compression
|
||||
|
||||
### `PNG`
|
||||
|
||||
```ts
|
||||
export interface PNGLosslessOptions {
|
||||
/**
|
||||
* Attempt to fix errors when decoding the input file rather than returning an Err.
|
||||
* Default: `false`
|
||||
*/
|
||||
fixErrors?: boolean | undefined | null
|
||||
/**
|
||||
* Write to output even if there was no improvement in compression.
|
||||
* Default: `false`
|
||||
*/
|
||||
force?: boolean | undefined | null
|
||||
/** Which filters to try on the file (0-5) */
|
||||
filter?: Array<number> | undefined | null
|
||||
/**
|
||||
* Whether to attempt bit depth reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
bitDepthReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt color type reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
colorTypeReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt palette reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
paletteReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt grayscale reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
grayscaleReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to perform IDAT recoding
|
||||
* If any type of reduction is performed, IDAT recoding will be performed regardless of this setting
|
||||
* Default: `true`
|
||||
*/
|
||||
idatRecoding?: boolean | undefined | null
|
||||
/** Whether to remove ***All non-critical headers*** on PNG */
|
||||
strip?: boolean | undefined | null
|
||||
/** Whether to use heuristics to pick the best filter and compression */
|
||||
useHeuristics?: boolean | undefined | null
|
||||
}
|
||||
export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
|
||||
```
|
||||
|
||||
### `JPEG`
|
||||
|
||||
```ts
|
||||
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 compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
|
||||
```
|
||||
18
__test__/lossless.spec.mjs
Normal file
18
__test__/lossless.spec.mjs
Normal file
@ -0,0 +1,18 @@
|
||||
import { promises as fs } from 'fs'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { losslessCompressPng, compressJpeg } from '../index.js'
|
||||
|
||||
const PNG = await fs.readFile('un-optimized.png')
|
||||
const JPEG = await fs.readFile('un-optimized.jpg')
|
||||
|
||||
test('should be able to lossless optimize png image', async (t) => {
|
||||
const dest = losslessCompressPng(PNG)
|
||||
t.true(dest.length < PNG.length)
|
||||
})
|
||||
|
||||
test('should be able to lossless optimize jpeg image', async (t) => {
|
||||
const dest = compressJpeg(JPEG, { quality: 100 })
|
||||
t.true(dest.length < PNG.length)
|
||||
})
|
||||
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
napi_build::setup();
|
||||
}
|
||||
66
index.d.ts
vendored
Normal file
66
index.d.ts
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/* auto-generated by NAPI-RS */
|
||||
|
||||
export class ExternalObject<T> {
|
||||
readonly '': {
|
||||
readonly '': unique symbol
|
||||
[K: symbol]: T
|
||||
}
|
||||
}
|
||||
export interface PNGLosslessOptions {
|
||||
/**
|
||||
* Attempt to fix errors when decoding the input file rather than returning an Err.
|
||||
* Default: `false`
|
||||
*/
|
||||
fixErrors?: boolean | undefined | null
|
||||
/**
|
||||
* Write to output even if there was no improvement in compression.
|
||||
* Default: `false`
|
||||
*/
|
||||
force?: boolean | undefined | null
|
||||
/** Which filters to try on the file (0-5) */
|
||||
filter?: Array<number> | undefined | null
|
||||
/**
|
||||
* Whether to attempt bit depth reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
bitDepthReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt color type reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
colorTypeReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt palette reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
paletteReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to attempt grayscale reduction
|
||||
* Default: `true`
|
||||
*/
|
||||
grayscaleReduction?: boolean | undefined | null
|
||||
/**
|
||||
* Whether to perform IDAT recoding
|
||||
* If any type of reduction is performed, IDAT recoding will be performed regardless of this setting
|
||||
* Default: `true`
|
||||
*/
|
||||
idatRecoding?: boolean | undefined | null
|
||||
/** Whether to remove ***All non-critical headers*** on PNG */
|
||||
strip?: boolean | undefined | null
|
||||
/** Whether to use heuristics to pick the best filter and compression */
|
||||
useHeuristics?: boolean | undefined | null
|
||||
}
|
||||
export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer
|
||||
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 compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer
|
||||
209
index.js
Normal file
209
index.js
Normal file
@ -0,0 +1,209 @@
|
||||
const { existsSync, readFileSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
|
||||
const { platform, arch } = process
|
||||
|
||||
let nativeBinding = null
|
||||
let localFileExisted = false
|
||||
let loadError = null
|
||||
|
||||
function isMusl() {
|
||||
// For Node 10
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
try {
|
||||
return readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
return !Boolean(glibcVersionRuntime)
|
||||
}
|
||||
}
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
if (arch !== 'arm64') {
|
||||
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
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.win32-x64-msvc.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.win32-x64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-win32-x64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.win32-ia32-msvc.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.win32-ia32-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-win32-ia32-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.win32-arm64-msvc.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.win32-arm64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-win32-arm64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'darwin':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.darwin-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.darwin-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-darwin-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.darwin-arm64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.darwin-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-darwin-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, 'image.freebsd-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.freebsd-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-freebsd-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(join(__dirname, 'image.linux-x64-musl.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.linux-x64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-linux-x64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(join(__dirname, 'image.linux-x64-gnu.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.linux-x64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-linux-x64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(join(__dirname, 'image.linux-arm64-musl.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.linux-arm64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-linux-arm64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(join(__dirname, 'image.linux-arm64-gnu.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.linux-arm64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-linux-arm64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(join(__dirname, 'image.linux-arm-gnueabihf.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./image.linux-arm-gnueabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('@napi-rs/image-linux-arm-gnueabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
||||
}
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError
|
||||
}
|
||||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { losslessCompressPng, compressJpeg } = nativeBinding
|
||||
|
||||
module.exports.losslessCompressPng = losslessCompressPng
|
||||
module.exports.compressJpeg = compressJpeg
|
||||
3
npm/android-arm-eabi/README.md
Normal file
3
npm/android-arm-eabi/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-android-arm-eabi`
|
||||
|
||||
This is the **armv7-linux-androideabi** binary for `@napi-rs/image`
|
||||
37
npm/android-arm-eabi/package.json
Normal file
37
npm/android-arm-eabi/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-android-arm-eabi",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"main": "image.android-arm-eabi.node",
|
||||
"files": [
|
||||
"image.android-arm-eabi.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/android-arm64/README.md
Normal file
3
npm/android-arm64/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-android-arm64`
|
||||
|
||||
This is the **aarch64-linux-android** binary for `@napi-rs/image`
|
||||
37
npm/android-arm64/package.json
Normal file
37
npm/android-arm64/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-android-arm64",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"main": "image.android-arm64.node",
|
||||
"files": [
|
||||
"image.android-arm64.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/darwin-arm64/README.md
Normal file
3
npm/darwin-arm64/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-darwin-arm64`
|
||||
|
||||
This is the **aarch64-apple-darwin** binary for `@napi-rs/image`
|
||||
37
npm/darwin-arm64/package.json
Normal file
37
npm/darwin-arm64/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-darwin-arm64",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"main": "image.darwin-arm64.node",
|
||||
"files": [
|
||||
"image.darwin-arm64.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/darwin-x64/README.md
Normal file
3
npm/darwin-x64/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-darwin-x64`
|
||||
|
||||
This is the **x86_64-apple-darwin** binary for `@napi-rs/image`
|
||||
37
npm/darwin-x64/package.json
Normal file
37
npm/darwin-x64/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-darwin-x64",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "image.darwin-x64.node",
|
||||
"files": [
|
||||
"image.darwin-x64.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/freebsd-x64/README.md
Normal file
3
npm/freebsd-x64/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-freebsd-x64`
|
||||
|
||||
This is the **x86_64-unknown-freebsd** binary for `@napi-rs/image`
|
||||
37
npm/freebsd-x64/package.json
Normal file
37
npm/freebsd-x64/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-freebsd-x64",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "image.freebsd-x64.node",
|
||||
"files": [
|
||||
"image.freebsd-x64.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/linux-arm-gnueabihf/README.md
Normal file
3
npm/linux-arm-gnueabihf/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-linux-arm-gnueabihf`
|
||||
|
||||
This is the **armv7-unknown-linux-gnueabihf** binary for `@napi-rs/image`
|
||||
37
npm/linux-arm-gnueabihf/package.json
Normal file
37
npm/linux-arm-gnueabihf/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-linux-arm-gnueabihf",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"main": "image.linux-arm-gnueabihf.node",
|
||||
"files": [
|
||||
"image.linux-arm-gnueabihf.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/linux-arm64-gnu/README.md
Normal file
3
npm/linux-arm64-gnu/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-linux-arm64-gnu`
|
||||
|
||||
This is the **aarch64-unknown-linux-gnu** binary for `@napi-rs/image`
|
||||
13
npm/linux-arm64-gnu/install.js
Normal file
13
npm/linux-arm64-gnu/install.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Node.js 10.x, ignore
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Only GNU system has this field
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
|
||||
if (glibcVersionRuntime) {
|
||||
process.exit(0)
|
||||
} else {
|
||||
process.exit(1)
|
||||
}
|
||||
41
npm/linux-arm64-gnu/package.json
Normal file
41
npm/linux-arm64-gnu/package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@napi-rs/image-linux-arm64-gnu",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"main": "image.linux-arm64-gnu.node",
|
||||
"files": [
|
||||
"image.linux-arm64-gnu.node",
|
||||
"install.js"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/linux-arm64-musl/README.md
Normal file
3
npm/linux-arm64-musl/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-linux-arm64-musl`
|
||||
|
||||
This is the **aarch64-unknown-linux-musl** binary for `@napi-rs/image`
|
||||
13
npm/linux-arm64-musl/install.js
Normal file
13
npm/linux-arm64-musl/install.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Node.js 10.x, ignore
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Only GNU system has this field
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
|
||||
if (glibcVersionRuntime) {
|
||||
process.exit(1)
|
||||
} else {
|
||||
process.exit(0)
|
||||
}
|
||||
41
npm/linux-arm64-musl/package.json
Normal file
41
npm/linux-arm64-musl/package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@napi-rs/image-linux-arm64-musl",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"main": "image.linux-arm64-musl.node",
|
||||
"files": [
|
||||
"image.linux-arm64-musl.node",
|
||||
"install.js"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/linux-x64-gnu/README.md
Normal file
3
npm/linux-x64-gnu/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-linux-x64-gnu`
|
||||
|
||||
This is the **x86_64-unknown-linux-gnu** binary for `@napi-rs/image`
|
||||
13
npm/linux-x64-gnu/install.js
Normal file
13
npm/linux-x64-gnu/install.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Node.js 10.x, ignore
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Only GNU system has this field
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
|
||||
if (glibcVersionRuntime) {
|
||||
process.exit(0)
|
||||
} else {
|
||||
process.exit(1)
|
||||
}
|
||||
41
npm/linux-x64-gnu/package.json
Normal file
41
npm/linux-x64-gnu/package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@napi-rs/image-linux-x64-gnu",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "image.linux-x64-gnu.node",
|
||||
"files": [
|
||||
"image.linux-x64-gnu.node",
|
||||
"install.js"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/linux-x64-musl/README.md
Normal file
3
npm/linux-x64-musl/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-linux-x64-musl`
|
||||
|
||||
This is the **x86_64-unknown-linux-musl** binary for `@napi-rs/image`
|
||||
13
npm/linux-x64-musl/install.js
Normal file
13
npm/linux-x64-musl/install.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Node.js 10.x, ignore
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Only GNU system has this field
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
|
||||
if (glibcVersionRuntime) {
|
||||
process.exit(1)
|
||||
} else {
|
||||
process.exit(0)
|
||||
}
|
||||
41
npm/linux-x64-musl/package.json
Normal file
41
npm/linux-x64-musl/package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@napi-rs/image-linux-x64-musl",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "image.linux-x64-musl.node",
|
||||
"files": [
|
||||
"image.linux-x64-musl.node",
|
||||
"install.js"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/win32-ia32-msvc/README.md
Normal file
3
npm/win32-ia32-msvc/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-win32-ia32-msvc`
|
||||
|
||||
This is the **i686-pc-windows-msvc** binary for `@napi-rs/image`
|
||||
37
npm/win32-ia32-msvc/package.json
Normal file
37
npm/win32-ia32-msvc/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-win32-ia32-msvc",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"main": "image.win32-ia32-msvc.node",
|
||||
"files": [
|
||||
"image.win32-ia32-msvc.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
3
npm/win32-x64-msvc/README.md
Normal file
3
npm/win32-x64-msvc/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# `@napi-rs/image-win32-x64-msvc`
|
||||
|
||||
This is the **x86_64-pc-windows-msvc** binary for `@napi-rs/image`
|
||||
37
npm/win32-x64-msvc/package.json
Normal file
37
npm/win32-x64-msvc/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@napi-rs/image-win32-x64-msvc",
|
||||
"version": "0.0.0",
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"main": "image.win32-x64-msvc.node",
|
||||
"files": [
|
||||
"image.win32-x64-msvc.node"
|
||||
],
|
||||
"description": "Image processing library",
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "git@github.com:Brooooooklyn/imgquant.git"
|
||||
}
|
||||
7
optimize-test.js
Normal file
7
optimize-test.js
Normal file
@ -0,0 +1,7 @@
|
||||
const { readFileSync, writeFileSync } = require('fs')
|
||||
|
||||
const { losslessCompressPng, compressJpeg } = require('./index')
|
||||
|
||||
writeFileSync('optimized-lossless.png', losslessCompressPng(readFileSync('./un-optimized.png')))
|
||||
|
||||
writeFileSync('optimized-lossless.jpg', compressJpeg(readFileSync('./un-optimized.jpg')))
|
||||
83
package.json
Normal file
83
package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "@napi-rs/image",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"description": "Image processing library",
|
||||
"author": {
|
||||
"email": "github@lyn.one",
|
||||
"name": "LongYinan",
|
||||
"url": "https://lyn.one"
|
||||
},
|
||||
"keywords": [
|
||||
"image",
|
||||
"lossless",
|
||||
"compression",
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"access": "public"
|
||||
},
|
||||
"napi": {
|
||||
"name": "image",
|
||||
"triples": {
|
||||
"additional": [
|
||||
"aarch64-apple-darwin",
|
||||
"aarch64-linux-android",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
"i686-pc-windows-msvc",
|
||||
"armv7-linux-androideabi"
|
||||
]
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||
},
|
||||
"scripts": {
|
||||
"artifacts": "napi artifacts",
|
||||
"build": "napi build --platform --release",
|
||||
"build:debug": "napi build --platform",
|
||||
"format": "run-p format:prettier format:rs",
|
||||
"format:prettier": "prettier --config ./package.json -w .",
|
||||
"format:rs": "cargo fmt --all",
|
||||
"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"
|
||||
}
|
||||
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
@ -0,0 +1,2 @@
|
||||
tab_spaces = 2
|
||||
edition = "2021"
|
||||
185
src/lib.rs
Normal file
185
src/lib.rs
Normal file
@ -0,0 +1,185 @@
|
||||
#![deny(clippy::all)]
|
||||
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use napi::{bindgen_prelude::*, JsBuffer};
|
||||
use napi_derive::napi;
|
||||
|
||||
#[napi(object, js_name = "PNGLosslessOptions")]
|
||||
#[derive(Default)]
|
||||
pub struct PNGLosslessOptions {
|
||||
/// Attempt to fix errors when decoding the input file rather than returning an Err.
|
||||
/// Default: `false`
|
||||
pub fix_errors: Option<bool>,
|
||||
/// Write to output even if there was no improvement in compression.
|
||||
/// Default: `false`
|
||||
pub force: Option<bool>,
|
||||
/// Which filters to try on the file (0-5)
|
||||
pub filter: Option<Vec<u32>>,
|
||||
/// Whether to attempt bit depth reduction
|
||||
/// Default: `true`
|
||||
pub bit_depth_reduction: Option<bool>,
|
||||
/// Whether to attempt color type reduction
|
||||
/// Default: `true`
|
||||
pub color_type_reduction: Option<bool>,
|
||||
/// Whether to attempt palette reduction
|
||||
/// Default: `true`
|
||||
pub palette_reduction: Option<bool>,
|
||||
/// Whether to attempt grayscale reduction
|
||||
/// Default: `true`
|
||||
pub grayscale_reduction: Option<bool>,
|
||||
/// Whether to perform IDAT recoding
|
||||
/// If any type of reduction is performed, IDAT recoding will be performed regardless of this setting
|
||||
/// Default: `true`
|
||||
pub idat_recoding: Option<bool>,
|
||||
/// Whether to remove ***All non-critical headers*** on PNG
|
||||
pub strip: Option<bool>,
|
||||
/// Whether to use heuristics to pick the best filter and compression
|
||||
pub use_heuristics: Option<bool>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_oxipng_options(options: Option<PNGLosslessOptions>) -> oxipng::Options {
|
||||
let opt = options.unwrap_or_default();
|
||||
oxipng::Options {
|
||||
fix_errors: opt.fix_errors.unwrap_or(false),
|
||||
force: opt.force.unwrap_or(false),
|
||||
filter: opt
|
||||
.filter
|
||||
.map(|v| v.into_iter().map(|i| i as u8).collect())
|
||||
.unwrap_or_else(|| oxipng::IndexSet::from_iter(0..5)),
|
||||
bit_depth_reduction: opt.bit_depth_reduction.unwrap_or(true),
|
||||
color_type_reduction: opt.color_type_reduction.unwrap_or(true),
|
||||
palette_reduction: opt.palette_reduction.unwrap_or(true),
|
||||
grayscale_reduction: opt.grayscale_reduction.unwrap_or(true),
|
||||
idat_recoding: opt.idat_recoding.unwrap_or(true),
|
||||
strip: opt
|
||||
.strip
|
||||
.map(|s| {
|
||||
if s {
|
||||
oxipng::Headers::All
|
||||
} else {
|
||||
oxipng::Headers::None
|
||||
}
|
||||
})
|
||||
.unwrap_or(oxipng::Headers::All),
|
||||
use_heuristics: opt.use_heuristics.unwrap_or(true),
|
||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))]
|
||||
deflate: oxipng::Deflaters::Libdeflater,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn lossless_compress_png(input: Buffer, options: Option<PNGLosslessOptions>) -> Result<Buffer> {
|
||||
let output = oxipng::optimize_from_memory(input.as_ref(), &to_oxipng_options(options))
|
||||
.map_err(|err| Error::new(Status::InvalidArg, format!("Optimize failed {}", err)))?;
|
||||
Ok(output.into())
|
||||
}
|
||||
|
||||
#[napi(object)]
|
||||
#[derive(Default)]
|
||||
pub struct JpegCompressOptions {
|
||||
/// Output quality, default is 100 (lossless)
|
||||
pub quality: Option<u32>,
|
||||
/// If true, it will use MozJPEG’s scan optimization. Makes progressive image files smaller.
|
||||
/// Default is `true`
|
||||
pub optimize_scans: Option<bool>,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub unsafe fn compress_jpeg(
|
||||
env: Env,
|
||||
input: Buffer,
|
||||
options: Option<JpegCompressOptions>,
|
||||
) -> Result<JsBuffer> {
|
||||
std::panic::catch_unwind(|| {
|
||||
let opts = options.unwrap_or_default();
|
||||
let mut de_c_info: mozjpeg_sys::jpeg_decompress_struct = std::mem::zeroed();
|
||||
let mut err_handler = create_error_handler();
|
||||
de_c_info.common.err = &mut err_handler;
|
||||
mozjpeg_sys::jpeg_create_decompress(&mut de_c_info);
|
||||
let input_buf = input.as_ref();
|
||||
#[cfg(any(target_os = "windows", target_arch = "arm"))]
|
||||
mozjpeg_sys::jpeg_mem_src(&mut de_c_info, input_buf.as_ptr(), input_buf.len() as u32);
|
||||
#[cfg(not(any(target_os = "windows", target_arch = "arm")))]
|
||||
mozjpeg_sys::jpeg_mem_src(&mut de_c_info, input_buf.as_ptr(), input_buf.len() as u64);
|
||||
let mut compress_c_info: mozjpeg_sys::jpeg_compress_struct = std::mem::zeroed();
|
||||
compress_c_info.optimize_coding = 1;
|
||||
compress_c_info.common.err = &mut err_handler;
|
||||
mozjpeg_sys::jpeg_create_compress(&mut compress_c_info);
|
||||
mozjpeg_sys::jpeg_read_header(&mut de_c_info, 1);
|
||||
let src_coef_arrays = mozjpeg_sys::jpeg_read_coefficients(&mut de_c_info);
|
||||
mozjpeg_sys::jpeg_copy_critical_parameters(&de_c_info, &mut compress_c_info);
|
||||
if let Some(quality) = opts.quality {
|
||||
mozjpeg_sys::jpeg_set_quality(&mut compress_c_info, quality as i32, 0);
|
||||
}
|
||||
if opts.optimize_scans.unwrap_or(true) {
|
||||
mozjpeg_sys::jpeg_c_set_bool_param(
|
||||
&mut compress_c_info,
|
||||
mozjpeg_sys::J_BOOLEAN_PARAM::JBOOLEAN_OPTIMIZE_SCANS,
|
||||
1,
|
||||
);
|
||||
}
|
||||
mozjpeg_sys::jpeg_c_set_int_param(
|
||||
&mut compress_c_info,
|
||||
mozjpeg_sys::J_INT_PARAM::JINT_DC_SCAN_OPT_MODE,
|
||||
0,
|
||||
);
|
||||
let mut buf = std::ptr::null_mut();
|
||||
let mut outsize = 0;
|
||||
mozjpeg_sys::jpeg_mem_dest(&mut compress_c_info, &mut buf, &mut outsize);
|
||||
mozjpeg_sys::jpeg_write_coefficients(&mut compress_c_info, src_coef_arrays);
|
||||
mozjpeg_sys::jpeg_finish_compress(&mut compress_c_info);
|
||||
mozjpeg_sys::jpeg_finish_decompress(&mut de_c_info);
|
||||
env
|
||||
.create_buffer_with_borrowed_data(
|
||||
buf,
|
||||
outsize as usize,
|
||||
(de_c_info, compress_c_info, buf),
|
||||
|(mut input, mut output, buf), _| {
|
||||
mozjpeg_sys::jpeg_destroy_decompress(&mut input);
|
||||
mozjpeg_sys::jpeg_destroy_compress(&mut output);
|
||||
libc::free(buf as *mut std::ffi::c_void);
|
||||
},
|
||||
)
|
||||
.map(|v| v.into_raw())
|
||||
})
|
||||
.map_err(|err| {
|
||||
Error::new(
|
||||
Status::GenericFailure,
|
||||
format!("Compress JPEG failed {:?}", err),
|
||||
)
|
||||
})
|
||||
.and_then(|v| v)
|
||||
}
|
||||
|
||||
unsafe fn create_error_handler() -> mozjpeg_sys::jpeg_error_mgr {
|
||||
let mut err: mozjpeg_sys::jpeg_error_mgr = std::mem::zeroed();
|
||||
mozjpeg_sys::jpeg_std_error(&mut err);
|
||||
err.error_exit = Some(unwind_error_exit);
|
||||
err.emit_message = Some(silence_message);
|
||||
err
|
||||
}
|
||||
|
||||
extern "C" fn unwind_error_exit(cinfo: &mut mozjpeg_sys::jpeg_common_struct) {
|
||||
let message = unsafe {
|
||||
let err = cinfo.err.as_ref().unwrap();
|
||||
match err.format_message {
|
||||
Some(fmt) => {
|
||||
let buffer = std::mem::zeroed();
|
||||
fmt(cinfo, &buffer);
|
||||
let len = buffer.iter().take_while(|&&c| c != 0).count();
|
||||
String::from_utf8_lossy(&buffer[..len]).into()
|
||||
}
|
||||
None => format!("libjpeg error: {}", err.msg_code),
|
||||
}
|
||||
};
|
||||
std::panic::resume_unwind(Box::new(message))
|
||||
}
|
||||
|
||||
extern "C" fn silence_message(
|
||||
_cinfo: &mut mozjpeg_sys::jpeg_common_struct,
|
||||
_level: std::os::raw::c_int,
|
||||
) {
|
||||
}
|
||||
BIN
un-optimized.jpg
Normal file
BIN
un-optimized.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
BIN
un-optimized.png
Normal file
BIN
un-optimized.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 886 KiB |
Loading…
x
Reference in New Issue
Block a user