Skip to content

Adding the ability to use a custom configuration #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions .optimiztrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import removeUnknownsAndDefaults from './svgo/removeUnknownsAndDefaults.cjs';

export default {
optimize: {
jpeg: {
// https://sharp.pixelplumbing.com/api-output#jpeg
lossy: {
quality: 80, // quality, integer 1-100
progressive: true, // use progressive (interlace) scan
chromaSubsampling: '4:2:0', // set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling
optimizeCoding: true, // optimise Huffman coding tables
mozjpeg: false, // use mozjpeg defaults, equivalent to { trellisQuantisation: true, overshootDeringing: true, optimiseScans: true, quantisationTable: 3 }
trellisQuantisation: false, // apply trellis quantisation
overshootDeringing: false, // apply overshoot deringing
optimizeScans: false, // optimise progressive scans, forces progressive
quantizationTable: 0, // quantization table to use, integer 0-8
},
// https://github.com/google/guetzli
lossless: {
quality: 90, // visual quality to aim for, expressed as a JPEG quality value
memlimit: 6000, // memory limit in MB; guetzli will fail if unable to stay under the limit
nomemlimit: false, // do not limit memory usage
},
},

// https://sharp.pixelplumbing.com/api-output#png
png: {
lossy: {
progressive: false, // use progressive (interlace) scan
compressionLevel: 9, // zlib compression level, 0 (fastest, largest) to 9 (slowest, smallest)
adaptiveFiltering: false, // use adaptive row filtering
palette: true, // quantise to a palette-based image with alpha transparency support
quality: 100, // use the lowest number of colours needed to achieve given quality, sets palette to true
effort: 7, // CPU effort, between 1 (fastest) and 10 (slowest), sets palette to true
colors: 256, // maximum number of palette entries, sets palette to true
dither: 1.0, // level of Floyd-Steinberg error diffusion, sets palette to true
},
lossless: {
progressive: false,
compressionLevel: 9,
adaptiveFiltering: true,
palette: false,
quality: 100,
effort: 7,
colors: 256,
dither: 1.0,
},
},

// http://www.lcdf.org/gifsicle/man.html
gif: {
lossy: {
optimize: 3, // attempt to shrink the file sizes of GIF animations; higher levels take longer, but may have better results; there are currently three levels
careful: false, // write larger GIFs that avoid bugs in other programs
colors: 256, // reduce the number of distinct colors to num or less; must be between 2 and 256
lossy: 100, // alter image colors to shrink output file size at the cost of artifacts and noise
},
lossless: {
optimize: 0,
careful: true,
colors: 256,
lossy: 0,
},
},

// https://github.com/svg/svgo#configuration
svg: {
multipass: true,
js2svg: {
pretty: true,
indent: 2,
},
plugins: [
/*
We want to remove useless parts of SVG, but to leave `stroke="none"`.
For this purpose we use here a custom version of `removeUnknownsAndDefaults`.
*/
{
name: 'removeUnknownsAndDefaults',
...removeUnknownsAndDefaults,
},

'cleanupAttrs',
'mergeStyles',
'inlineStyles',
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeTitle',
'removeDesc',
'removeUselessDefs',
'removeEditorsNSData',
'removeEmptyAttrs',
'removeHiddenElems',
'removeEmptyText',
'removeEmptyContainers',
'cleanupEnableBackground',
'minifyStyles',
'convertStyleToAttrs',
'convertColors',
'convertPathData',
'convertTransform',
'removeNonInheritableGroupAttrs',
'removeUnusedNS',
'cleanupIDs',
'cleanupNumericValues',
'cleanupListOfValues',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
'mergePaths',
'convertShapeToPath',
'convertEllipseToCircle',
'sortAttrs',
'sortDefsChildren',
'removeOffCanvasPaths',
'reusePaths',
],
},
},

convert: {
// https://sharp.pixelplumbing.com/api-output#avif
avif: {
lossy: {
quality: 50, // quality, integer 1-100
lossless: false, // use lossless compression
effort: 4, // CPU effort, between 0 (fastest) and 9 (slowest)
chromaSubsampling: '4:4:4', // set to '4:2:0' to use chroma subsampling
},
lossless: {
quality: 50,
lossless: true,
effort: 4,
chromaSubsampling: '4:4:4',
},
},

// https://sharp.pixelplumbing.com/api-output#webp
webp: {
lossy: {
quality: 85, // quality, integer 1-100
alphaQuality: 100, // quality of alpha layer, integer 0-100
lossless: false, // use lossless compression mode
nearLossless: false, // use near_lossless compression mode
smartSubsample: false, // use high quality chroma subsampling
effort: 4, // CPU effort, between 0 (fastest) and 6 (slowest)
minSize: false, // prevent use of animation key frames to minimise file size (slow)
mixed: false, // allow mixture of lossy and lossless animation frames (slow)
},
lossless: {
quality: 85,
alphaQuality: 100,
lossless: true,
nearLossless: false,
smartSubsample: false,
effort: 4,
minSize: false,
mixed: false,
},
},

// TODO: Replace gif2webp with sharp
// https://developers.google.com/speed/webp/docs/gif2webp
webpGif: {
lossy: {
lossy: true, // encode image using lossy compression
mixed: false, // for each frame in the image, pick lossy or lossless compression heuristically
q: 75, // in case of lossy compression, a small factor produces a smaller file with lower quality; best quality is achieved by using a value of 100
m: 6, // compression method (0=fast, 6=slowest)
min_size: true, // minimize output size; can be combined with -q, -m, -lossy or -mixed options
f: 0, // filter strength (0=off..100); for lossy encoding only
metadata: 'xmp', // comma separated list of metadata to copy from the input to the output if present; valid values: all, none, icc, xmp
loop_compatibility: false, // use compatibility mode for Chrome version prior to M62 (inclusive)
mt: true, // use multi-threading if available
},
lossless: {
lossy: false,
mixed: false,
q: 100,
m: false,
min_size: false,
metadata: 'xmp',
loop_compatibility: false,
mt: true,
},
},
},
};
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Changelog

## 4.1.0 (27.01.2023)

Added `--config` flag, which allows specifying path to file with custom settings.

See more in README.


## 4.0.0 (27.05.2022)

This package is now pure ESM.

JPEG files now processed via sharp module.
In lossy mode, JPEG files are now processed by sharp module.


## 3.1.2 (06.05.2022)
Expand Down
68 changes: 29 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ optimizt path/to/picture.jpg

- `--avif` — create AVIF versions for the passed paths instead of compressing them.
- `--webp` — create WebP versions for the passed paths instead of compressing them.
- `--force` — force create AVIF and WebP even if output file size increased or file already exists.
- `-f, --force` — force create AVIF and WebP even if output file size increased or file already exists.
- `-l, --lossless` — optimize losslessly instead of lossily (WebP and AVIF only).
- `-v, --verbose` — show additional info, e.g. skipped files.
- `-c, --config` — use this configuration, overriding default config options if present.
- `-o, --output` — write result to provided directory.
- `-V, --version` — show tool version.
- `-h, --help` — show help.
Expand All @@ -62,58 +63,47 @@ optimizt --webp path/to/directory
find . -iname \*.jpg -exec optimizt {} +
```

## Differences between “lossy” and “lossless”
## Differences between Lossy and Lossless

### JPEG
### Lossy (by default)

#### Lossy
Allows you to obtain the final image with a balance between a high level of compression and a minimum level
of visual distortion.

[sharp](https://github.com/lovell/sharp) with [parameters](https://sharp.pixelplumbing.com/api-output#jpeg):
`progressive: true`.
### Lossless (--lossless flag)

#### Lossless
When creating AVIF and WebP versions, optimizations are applied that do not affect the visual quality of the images.

[Guetzli](https://github.com/google/guetzli) with `--quality 90` flag.
PNG, JPEG, and GIF optimization uses settings that maximize the visual quality of the image at the expense of
the final file size.

Guetzli aims for excellent compression density at high visual quality.
When processing SVG files, the settings for Lossy and Lossless modes are identical.

Keep in mind that if you reoptimize the same file in lossless mode, the file size may decrease, but the visual quality
will also degrade.
## Configuration

### PNG
[JPEG](https://sharp.pixelplumbing.com/api-output#jpeg), [PNG](https://sharp.pixelplumbing.com/api-output#png),
[WebP](https://sharp.pixelplumbing.com/api-output#webp), and [AVIF](https://sharp.pixelplumbing.com/api-output#avif)
processing is done using [sharp](https://github.com/lovell/sharp) library, while SVG is processed using
[svgo](https://github.com/svg/svgo) utility.

[sharp](https://github.com/lovell/sharp) with [parameters](https://sharp.pixelplumbing.com/api-output#png):
For optimizing GIFs, [gifsicle](https://github.com/kohler/gifsicle) is used, and for converting to WebP,
[gif2webp](https://developers.google.com/speed/webp/docs/gif2webp) is used.

- **lossy**: `compressionLevel: 9`, `adaptiveFiltering: false`, `palette: true`
- **lossless**: `compressionLevel: 9`, `adaptiveFiltering: true`, `palette: false`
> 💡 Lossless mode uses [Guetzli](https://github.com/google/guetzli) encoder to optimize JPEG, which allows to get
> a high level of compression and still have a good visual quality. But you should keep in mind that if you optimize
> the file again, the size may decrease at the expense of degrading the visual quality of the image.

### GIF
The default settings are located in [.optimiztrc.js](./.optimiztrc.js), the file contains a list of supported parameters
and their brief description.

[gifsicle](https://github.com/kohler/gifsicle) with flags:
To disable any of the parameters, you should use `false` for the value.

- **lossy**: `-O3`, `--lossy=100`
- **lossless**: no flags
When running with the `--config path/to/.optimiztrc.js` flag, the settings from the specified configuration file will
be used for image processing.

### WebP

[sharp](https://github.com/lovell/sharp) with [parameters](https://sharp.pixelplumbing.com/api-output#webp):

- **lossy**: `quality: 85`, `lossless: false`
- **lossless**: `quality: 85`, `lossless: true`

### WebP (GIF)

[gif2webp](https://developers.google.com/speed/webp/docs/gif2webp) with flags:

- **lossy**: `-lossy`, `-min_size`
- **lossless**: no flags

### AVIF

[sharp](https://github.com/lovell/sharp) with [parameters](https://sharp.pixelplumbing.com/api-output#avif):

- **lossy**: `lossless: false`
- **lossless**: `lossless: true`
When running normally, without the `--config` flag, a recursive search for the `.optimiztrc.js` file will be performed
starting from the current directory and up to the root of the file system. If the file is not found, the default
settings will be applied.

## Integrations

Expand Down
Loading