Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

Commit

Permalink
Merge development branch - v2.1.0 WebP optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcusCemes committed Mar 23, 2019
2 parents 2b8571b + 5752c71 commit 91cf78e
Show file tree
Hide file tree
Showing 15 changed files with 47 additions and 11 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ All keys in the configuration object have [Typescript](#typescript) typings that

**Note:** The supported keys for codec specific settings are:

- exportOriginal
- exportWebp
- resize
- optimize
Expand Down Expand Up @@ -395,19 +396,19 @@ Even without modern editor, you can consult the generated `*.d.ts` typing files

## Optimization

Image optimization uses *pngquant*, *mozjpeg*, *svgo*, *gifsicle* and *cwebp* to reduce the output image size as much as possible. By default, it's very aggressive, and also very slow. In most situations it will take more time than the resize process. If `optimize` is set to `false`, then the image will be saved directly from SHARP using default codec settings, instead of being sent to the optimizer first.
Image optimization uses *pngquant*, *mozjpeg*, *svgo* and *gifsicle* to reduce the output image size as much as possible. By default, it's very aggressive, and also very slow. In most situations it will take more time than the resize process. If `optimize` is set to `false`, then the image will be saved directly from SHARP using default codec settings, instead of being sent to the optimizer first.

You can override all of the optimizer settings by specifying the `optimizerSettings` key in the configuration object (must be under on of the `png`, `jpeg`, `svg` or `gif` keys).
You can override all of the optimizer settings by specifying the `optimizerSettings` key in the configuration object (must be under on of the `png`, `jpeg`, `svg`, `gif` or `webp` keys).

See [imagemin-pngquant](https://www.npmjs.com/package/imagemin-pngquant), [imagemin-mozjpeg](https://www.npmjs.com/package/imagemin-mozjpeg), [imagemin-svgo](https://www.npmjs.com/package/imagemin-svgo), [imagemin-gifsicle](https://www.npmjs.com/package/imagemin-gifsicle) and [imagemin-webp](https://www.npmjs.com/package/imagemin-webp) for the available optimization options.
See [imagemin-pngquant](https://www.npmjs.com/package/imagemin-pngquant), [imagemin-mozjpeg](https://www.npmjs.com/package/imagemin-mozjpeg), [imagemin-svgo](https://www.npmjs.com/package/imagemin-svgo) and [imagemin-gifsicle](https://www.npmjs.com/package/imagemin-gifsicle) for the available optimization options. For WebP, you must use the [SHARP configuration object](https://sharp.dimens.io/en/stable/api-output/#webp) instead, as `imagemin-webp` seems to have compatibility issues with libvips.

Usually WebP provides a ~40% difference in file reduction, however you may need to play around with the optimizer settings to achieve this. I have chosen some opinionated settings to try to achieve web-type compression. Specifying a an empty object `{}` as the `optimizerSettings` for the codec (in the config) will override the default settings and revert to the plugin defaults.

### Performance

RIB has been rewritten from the ground up to be more efficient than previous versions. Instead of writing vast quantities of raw image data to memory buffers for every operation, the new version leverages the performance of Node.js streams, reducing the memory footprint without sacrificing any speed.

For each image job, a tree-like stream network is created that flows data from the source image, through the resize and optimizer streams before being redirected back to the disk. This allows image data to flow through the network as needed until all write streams close, small packets at a time.
For each image job, a tree-like stream network (that is referred to as a pipeline in this documentation) is created that flows data from the source image, through the resize and optimizer stream modifiers before being redirected back to the disk. This allows image data to flow through the network as needed until all write streams close, small packets at a time.

On a high-end system, you may expect to process a thousand high-quality 4K images a minute with the default program configuration.

Expand All @@ -430,7 +431,7 @@ Please make sure that your contributions pass tests before submitting a Pull Req

It's hard to make short error messages easy to understand. You can find a description of the error here.

RIB error codes are formatted as the letter E, followed by four digits.
RIB error codes are formatted as the letter E, followed by three digits.

<details><summary><b>Error codes (click me)</b></summary>

Expand Down Expand Up @@ -462,6 +463,8 @@ Important files were detected in the output folder, and the user aborted the cle

The controller is in charge of the worker cluster and handles job delegation.

All errors are passed through the the Main class.

### Thread errors

These errors are thrown by the image processing thread.
Expand All @@ -481,15 +484,15 @@ An unlikely error, the image disappeared since the input directory was scanned d

#### E503 - Not a file

An unlikely error. The path for the image was no-longer a file.
An unlikely error. The path for the image was no longer a file.

</details>

## Built With

* [NodeJS](https://nodejs.org) - Powered by Chrome's V8 Javascript engine
* [SHARP](https://github.com/lovell/sharp) - A fantastic Node.js wrapper around the [libvips](https://github.com/jcupitt/libvips) library
* [Dynamic Terminal](https://github.com/marcuscemes/dynamic-terminal) My very own terminal logging library
* [Dynamic Terminal](https://github.com/marcuscemes/dynamic-terminal) - My very own terminal logging library

### Milestones

Expand All @@ -503,7 +506,6 @@ An unlikely error. The path for the image was no-longer a file.
- [ ] Support "synchronize" mode where only missing images are exported
- [ ] Add checksum to manifest for better image searching
- [ ] Add example with new WebP optimizer and better optimizer settings
- [ ] Consider removing dependency and use compiled encoders directly
- [x] Add exportOriginalCodec option
- [x] Add support for imagemin-webp [REVERTED DUE TO BUG]
- [x] Avoid double-compressing a file when optimizer is enabled
Expand Down
32 changes: 32 additions & 0 deletions example/EXAMPLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# An example Responsive Image Builder export

![The original Unsplash image](a-pretty-background.jpg)

<p align="center"><sub>
The original picture from Unsplash is 4MB. It measures 6000x4000.
</sub></p>
<br>

The export contains the pictures obtained with RIB using the default configuration. The standard-sized WebP image is only 134KB! That's roughly a 25% reduction in size and bandwidth compared to its identical JPEG twin.

This is the kind of reduction that you can expect from WebP while maintaining the same or slightly superior quality. By playing with the encoding settings, you could drive those file-sizes down even further.

See for your self!

<br>

![The resized JPEG image](export/a-pretty-background_normal.jpg)

<p align="center"><sub>
A decent 1620x1080 JPEG export that is 180KB
</sub></p>
<br>

![The resized WebP image](export/a-pretty-background_normal.webp)

<p align="center"><sub>
A superior 1620x1080 JPEG WebP that is 134KB. Can you tell the difference?
</sub></p>
<br>

Photo by Nathaniel Foong on [Unsplash](https://unsplash.com/photos/OVfKK18xzHA)
Binary file added example/a-pretty-background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/export/a-pretty-background_large.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/export/a-pretty-background_large.webp
Binary file not shown.
Binary file added example/export/a-pretty-background_normal.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/export/a-pretty-background_normal.webp
Binary file not shown.
Binary file added example/export/a-pretty-background_small.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/export/a-pretty-background_small.webp
Binary file not shown.
Binary file added example/export/a-pretty-background_thumbnail.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/export/a-pretty-background_thumbnail.webp
Binary file not shown.
1 change: 1 addition & 0 deletions example/export/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"exports":[{"name":"a-pretty-background","fullName":"a-pretty-background","extension":".jpg","webp":true,"sizes":[{"name":"thumbnail","width":16,"height":11},{"name":"small","width":1080,"height":720},{"name":"normal","width":1620,"height":1080,"default":true},{"name":"large","width":3240,"height":2160}]}]}
4 changes: 2 additions & 2 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export interface ICodecSettings {
* Enable/Disable image optimization.
* If disabled, the image will be saved directly from SHARP using default options.
* If enabled, the image will pass through an optimizer beforehand, which can be
* configured using optimizerSettings.
* configured using optimizerSettings. Doesn't do anything for WebP.
*/
optimize?: boolean;
/** imagemin plugin-specific settings */
/** imagemin plugin-specific settings, or the SHARP WebP options for WebP! */
optimizerSettings?: object;
/** The responsive breakpoints to use for resizing */
exportPresets?: IExportPreset[];
Expand Down
2 changes: 1 addition & 1 deletion src/ProcessThread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ class ProcessThread {
}

if (saveWebp && targetFormat !== "webp") {
const webpOptions = this.getOption("optimize", "webp") || {};
const webpOptions = this.getOption("optimizerSettings", "webp") || {};
const webpWriteStream = fs.createWriteStream(exportPath + ".webp", {
flags: writePermission
});
Expand Down
1 change: 1 addition & 0 deletions src/Utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ansiAlign from "ansi-align";
import sharp, { Sharp } from "sharp";
import wrapAnsi from "wrap-ansi";

/** Check if object is an instance of SHARP */
export function isSharpInstance(instance: object): instance is Sharp {
return instance instanceof sharp;
}
Expand Down

0 comments on commit 91cf78e

Please sign in to comment.