├── .npmrc ├── .gitattributes ├── .gitignore ├── index.js ├── test ├── fixtures │ └── test.jpg └── test.js ├── vendor ├── osx │ └── jpeg-recompress ├── linux │ └── jpeg-recompress ├── win │ └── jpeg-recompress.exe └── source │ └── jpeg-archive-2.2.0.tar.gz ├── cli.js ├── .editorconfig ├── lib ├── index.js └── install.js ├── .github └── workflows │ └── test.yml ├── readme.md ├── license └── package.json /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/tmp 3 | vendor/jpeg-recompress* 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import lib from './lib/index.js'; 2 | 3 | export default lib.path(); 4 | -------------------------------------------------------------------------------- /test/fixtures/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imagemin/jpeg-recompress-bin/HEAD/test/fixtures/test.jpg -------------------------------------------------------------------------------- /vendor/osx/jpeg-recompress: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imagemin/jpeg-recompress-bin/HEAD/vendor/osx/jpeg-recompress -------------------------------------------------------------------------------- /vendor/linux/jpeg-recompress: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imagemin/jpeg-recompress-bin/HEAD/vendor/linux/jpeg-recompress -------------------------------------------------------------------------------- /vendor/win/jpeg-recompress.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imagemin/jpeg-recompress-bin/HEAD/vendor/win/jpeg-recompress.exe -------------------------------------------------------------------------------- /vendor/source/jpeg-archive-2.2.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imagemin/jpeg-recompress-bin/HEAD/vendor/source/jpeg-archive-2.2.0.tar.gz -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import {spawn} from 'node:child_process'; 3 | import process from 'node:process'; 4 | import jpegRecompress from './index.js'; 5 | 6 | const input = process.argv.slice(2); 7 | 8 | spawn(jpegRecompress, input, {stdio: 'inherit'}) 9 | .on('exit', process.exit); 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.{json,yml}] 11 | indent_size = 2 12 | indent_style = space 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import process from 'node:process'; 3 | import {fileURLToPath} from 'node:url'; 4 | import BinWrapper from 'bin-wrapper'; 5 | 6 | const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url))); 7 | const url = `https://raw.github.com/imagemin/jpeg-recompress-bin/v${pkg.version}/vendor/`; 8 | 9 | const binWrapper = new BinWrapper() 10 | .src(`${url}osx/jpeg-recompress`, 'darwin') 11 | .src(`${url}linux/jpeg-recompress`, 'linux') 12 | .src(`${url}win/jpeg-recompress.exe`, 'win32') 13 | .dest(fileURLToPath(new URL('../vendor', import.meta.url))) 14 | .use(process.platform === 'win32' ? 'jpeg-recompress.exe' : 'jpeg-recompress'); 15 | 16 | export default binWrapper; 17 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | node-version: 12 | - 18 13 | - 16 14 | - 14 15 | os: 16 | - ubuntu-latest 17 | - macos-latest 18 | - windows-latest 19 | steps: 20 | - uses: actions/checkout@v2 21 | - if: contains(matrix.os, 'macos') 22 | run: brew install mozjpeg 23 | - uses: actions/setup-node@v2 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - run: npm install 27 | - run: npm test 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # jpeg-recompress-bin ![GitHub Actions Status](https://github.com/imagemin/jpeg-recompress-bin/workflows/test/badge.svg?branch=main) 2 | 3 | > Compress JPEGs by re-encoding to the smallest JPEG quality while keeping perceived visual quality the same and by making sure huffman tables are optimized 4 | 5 | You probably want [`imagemin-jpeg-recompress`](https://github.com/imagemin/imagemin-jpeg-recompress) instead. 6 | 7 | 8 | ## Install 9 | 10 | ``` 11 | $ npm install --save jpeg-recompress-bin 12 | ``` 13 | 14 | 15 | ## Usage 16 | 17 | ```js 18 | import {execFile} from 'node:child_process'; 19 | import jpegRecompress from 'jpeg-recompress-bin'; 20 | 21 | execFile(jpegRecompress, ['--quality high', '--min 60', 'input.jpg', 'output.jpg'], error => { 22 | console.log('Image minified'); 23 | }); 24 | ``` 25 | 26 | 27 | ## CLI 28 | 29 | ``` 30 | $ npm install --global jpeg-recompress-bin 31 | ``` 32 | 33 | ``` 34 | $ jpeg-recompress --help 35 | ``` 36 | 37 | 38 | ## License 39 | 40 | MIT © [Imagemin](https://github.com/imagemin) 41 | -------------------------------------------------------------------------------- /lib/install.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import {fileURLToPath} from 'node:url'; 3 | import binBuild from 'bin-build'; 4 | import bin from './index.js'; 5 | 6 | bin.run(['--version']).then(() => { 7 | console.log('jpeg-recompress pre-build test passed successfully'); 8 | }).catch(async error => { 9 | console.warn(error.message); 10 | console.warn('jpeg-recompress pre-build test failed'); 11 | 12 | if (process.platform === 'win32' || process.platform === 'linux') { 13 | // eslint-disable-next-line unicorn/no-process-exit 14 | process.exit(1); 15 | } 16 | 17 | console.info('compiling from source'); 18 | 19 | try { 20 | const source = fileURLToPath(new URL('../vendor/source/jpeg-archive-2.2.0.tar.gz', import.meta.url)); 21 | 22 | await binBuild.file(source, [ 23 | `mkdir -p ${bin.dest()}`, 24 | `make && mv ${bin.use()} ${bin.path()}`, 25 | ]); 26 | 27 | console.log('jpeg-recompress built successfully'); 28 | } catch (error) { 29 | console.error(error.stack); 30 | 31 | // eslint-disable-next-line unicorn/no-process-exit 32 | process.exit(1); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Imagemin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import process from 'node:process'; 4 | import {fileURLToPath} from 'node:url'; 5 | import test from 'ava'; 6 | import {execa} from 'execa'; 7 | import {temporaryDirectory} from 'tempy'; 8 | import binCheck from 'bin-check'; 9 | import binBuild from 'bin-build'; 10 | import compareSize from 'compare-size'; 11 | import jpegRecompress from '../index.js'; 12 | 13 | test('rebuild the jpeg-recompress binaries', async t => { 14 | if (process.platform === 'win32' || process.platform === 'linux') { 15 | t.pass('Build for win32 and linux is not supported'); 16 | return; 17 | } 18 | 19 | const temporary = temporaryDirectory(); 20 | const source = fileURLToPath(new URL('../vendor/source/jpeg-archive-2.2.0.tar.gz', import.meta.url)); 21 | 22 | await binBuild.file(source, [ 23 | `mkdir -p ${temporary}`, 24 | `make && mv jpeg-recompress ${path.join(temporary, 'jpeg-recompress')}`, 25 | ]); 26 | 27 | t.true(fs.existsSync(path.join(temporary, 'jpeg-recompress'))); 28 | }); 29 | 30 | test('return path to binary and verify that it is working', async t => { 31 | t.true(await binCheck(jpegRecompress, ['--version'])); 32 | }); 33 | 34 | test('minify a JPG', async t => { 35 | const temporary = temporaryDirectory(); 36 | const src = fileURLToPath(new URL('fixtures/test.jpg', import.meta.url)); 37 | const dest = path.join(temporary, 'test.jpg'); 38 | const args = [ 39 | '--quality', 40 | 'high', 41 | '--min', 42 | '60', 43 | src, 44 | dest, 45 | ]; 46 | 47 | await execa(jpegRecompress, args); 48 | const result = await compareSize(src, dest); 49 | 50 | t.true(result[dest] < result[src]); 51 | }); 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jpeg-recompress-bin", 3 | "version": "7.0.0", 4 | "description": "jpeg-recompress wrapper that makes it seamlessly available as a local dependency", 5 | "license": "MIT", 6 | "repository": "imagemin/jpeg-recompress-bin", 7 | "type": "module", 8 | "exports": "./index.js", 9 | "author": { 10 | "name": "Shogo Sensui", 11 | "email": "shogosensui@gmail.com", 12 | "url": "github.com/1000ch" 13 | }, 14 | "maintainers": [ 15 | { 16 | "name": "Sindre Sorhus", 17 | "email": "sindresorhus@gmail.com", 18 | "url": "sindresorhus.com" 19 | }, 20 | { 21 | "name": "Kevin Mårtensson", 22 | "email": "kevinmartensson@gmail.com", 23 | "url": "github.com/kevva" 24 | }, 25 | { 26 | "name": "Shinnosuke Watanabe", 27 | "url": "github.com/shinnn" 28 | } 29 | ], 30 | "bin": { 31 | "jpeg-recompress": "cli.js" 32 | }, 33 | "engines": { 34 | "node": "^14.13.1 || >=16.0.0" 35 | }, 36 | "scripts": { 37 | "postinstall": "node lib/install.js", 38 | "test": "xo && ava --timeout=120s" 39 | }, 40 | "files": [ 41 | "cli.js", 42 | "index.js", 43 | "lib", 44 | "vendor/source" 45 | ], 46 | "keywords": [ 47 | "imagemin", 48 | "compress", 49 | "image", 50 | "img", 51 | "jpeg", 52 | "jpg", 53 | "minify", 54 | "optimize", 55 | "jpeg-recompress" 56 | ], 57 | "dependencies": { 58 | "bin-build": "^3.0.0", 59 | "bin-wrapper": "^4.1.0" 60 | }, 61 | "devDependencies": { 62 | "ava": "^4.2.0", 63 | "bin-check": "^4.0.1", 64 | "compare-size": "^3.0.0", 65 | "execa": "^6.1.0", 66 | "tempy": "^3.0.0", 67 | "xo": "^0.48.0" 68 | } 69 | } 70 | --------------------------------------------------------------------------------