Skip to content

Commit

Permalink
Introduced "auto-limit" option which replaces setting "quality" to "a…
Browse files Browse the repository at this point in the history
…uto". Closes #281
  • Loading branch information
rosell-dk committed May 12, 2021
1 parent bcaa453 commit 1d162dd
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 37 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ The library can convert using the following methods:

In addition to converting, the library also has a method for *serving* converted images, and we have instructions here on how to set up a solution for automatically serving webp images to browsers that supports webp.

## 2.6.0 is coming up
Changes:
- Introduced "auto-limit" option which replaces setting "quality" to "auto"
- Made available converter options accessible - primarily in order to give GUI's a way to automatically adjust their setting screens
- Added "sharp-yuv" option and made it default on for png (in doubt if it should be default on for jpeg too). [Its great](https://www.ctrl.blog/entry/webp-sharp-yuv.html), use it! Works in most converters.
- Bumped cwebp binaries to 1.2.0
- vips now supports "method" option and "preset" option
- graphicsmagick now supports "auto-filter" potion
- vips, imagick, imagemagick, graphicsmagick and gmagick now supports "preset" option.


## Installation
Require the library with *Composer*, like this:

Expand Down
47 changes: 39 additions & 8 deletions docs/v2.0/converting/introduction-for-converting.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ I recommend leave the converters array at the default unless you have strong rea
### Example:

```php
<?php
use WebPConvert\Convert\Converters\Stack;

Stack::convert($source, $destination, $options = [
Expand Down Expand Up @@ -96,13 +95,13 @@ define('WEBPCONVERT_IMAGEMAGICK_PATH', '/usr/local/bin/magick');

## Configuring the options

### Auto quality
### Preventing unnecessarily high quality setting for low quality jpegs
**Q:** What do you get if you convert a low quality jpeg (ie q=50) into a high quality webp (ie q=90) ?\
**A:** You maintain the low quality, but you get a large file`

What should we have done instead? We should have converted with a quality around 50. Of course, quality is still low - we cannot fix that - but it will not be less, *and the converted file will be much smaller*.

As unnecessary large conversions are rarely desirable, this library per default converts jpeg files with the same quality level as the source. This functionality requires that either *imagemagick*, *graphicsmagick* or *imagick* is installed (not necessarily compiled with webp support). When they are, all converters will have the "auto" quality functionality. The *wpc* cloud converter supports auto quality if these are installed on the server that *wpc* is installed on.
As unnecessary large conversions are rarely desirable, this library per default converts jpeg files with the same quality level as the source. This functionality requires that either *imagemagick*, *graphicsmagick* or *imagick* is installed (not necessarily compiled with webp support). When they are, all converters will have the "auto" quality functionality. Otherwise, only *wpc* will support it (provided that one of these libraries is installed on the server of the cloud service).

How much can be gained? A lot!
The following low quality (q=50) jpeg weighs 54 kb. If this is converted to webp with quality=80, the size of the converted file is 52kb - almost no reduction! With auto, the quality of the webp will be set to 50, and the size will be 34kb. Visually, the results are indistinguable.
Expand All @@ -112,9 +111,7 @@ The following low quality (q=50) jpeg weighs 54 kb. If this is converted to webp
**Q:** What do you get if you convert an excessively high quality jpeg into an excessively high quality webp?\
**A:** An excessively big file

The size of a webp file grows enormously with the quality setting. For the web however, a quality above 80 is rarely needed. For this reason the library has a per default limits the quality to the value of the *max-quality* option (default: 85).

In case quality detection is unavailable, the quality gets the value of the *default-quality* option (default is 70 for JPEGs and 85 for PNGs).
The size of a webp file grows enormously with the quality setting. For the web however, a quality above 75 is rarely needed. For this reason the library has a per default sets the quality to 75 for jpegs.

So, how much can be gained? A lot!
The following excessively high quality jpeg (q=100) weighs 146 kb. Converting it to webp with q=100 results in a 99kb image (this would happen if we had the auto feature, but not the max-quality feature). Converting it to q=85 results in a 40kb image.
Expand Down Expand Up @@ -160,7 +157,7 @@ libwebp has an overlooked option which improves accuracy for RGB to YUV mapping

To have options depending on the image type of the source, you can use the `png` and `jpeg` keys.

The following options mimics the default behaviour:
The following options mimics the default behaviour (version 2.0 - 2.5):

```php
$options = [
Expand All @@ -179,8 +176,28 @@ $options = [
]
];
```
PS: From version 2.6 on, you should use the new "auto-limit" option instead of setting quality to "auto".

The following options mimics the default behaviour (version 2.6 and forth):

You can use it for any option, also the converter specific options.
```php
$options = [
'png' => [
'encoding' => 'auto', /* Try both lossy and lossless and pick smallest */
'near-lossless' => 60, /* The level of near-lossless image preprocessing (when trying lossless) */
'quality' => 85, /* Quality when trying lossy. It is set high because pngs is often selected to ensure high quality */
'sharp-yuv' => true,
],
'jpeg' => [
'encoding' => 'auto', /* If you are worried about the longer conversion time, you could set it to "lossy" instead (lossy will often be smaller than lossless for jpegs) */
'quality' => 75, /* Quality when trying lossy. It is set a bit lower for jpeg than png */
'auto-limit' => true, /* Prevents using a higher quality than that of the source (requires imagick or gmagick extension, not necessarily compiled with webp) */
'sharp-yuv' => true,
]
];
```

The *png* and *jpeg* options can hold any other option - also the converter specific options.
A use case could for example be to use different converters for png and jpeg:

```php
Expand All @@ -200,6 +217,8 @@ $options = [

Here is a quick overview of the few ones discussed here.

### Version 2.0 - 2.5

| Option | Default (jpeg) | Default (png) | Description |
| ----------------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------- |
| quality | "auto" | 85 | See the "Auto quality" section above. |
Expand All @@ -211,6 +230,18 @@ Here is a quick overview of the few ones discussed here.
| png | - | - | Array of options which will be merged into the other options when source is a PNG |
| skip | false | false | If true, conversion will be skipped (ie for skipping png conversion for some converters) |

### Version > 2.6

| Option | Default (jpeg) | Default (png) | Description |
| ----------------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------- |
| quality | 75 | 85 | Quality for lossy encoding |
| auto-limit | true | true | Only relevant for jpegs and lossy encoding |
| metadata | "none" | "none" | Valid values: "all", "none", "exif", "icc", "xmp".<br><br>Note: Currently only *cwebp* supports all values. *gd* will always remove all metadata. *ewww*, *imagick* and *gmagick* can either strip all, or keep all (they will keep all, unless metadata is set to *none*) |
| encoding | "auto" | "auto" | See the "Auto selecting between lossless/lossy encoding" section above |
| jpeg | - | - | Array of options which will be merged into the other options when source is a JPEG |
| png | - | - | Array of options which will be merged into the other options when source is a PNG |
| skip | false | false | If true, conversion will be skipped (ie for skipping png conversion for some converters) |


## More info

Expand Down
22 changes: 15 additions & 7 deletions docs/v2.0/converting/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ Supported by: cwebp, vips, imagick, gmagick, imagemagick and graphicsmagick
```
Turns auto-filter on. This algorithm will spend additional time optimizing the filtering strength to reach a well-balanced quality. Unfortunately, it is extremely expensive in terms of computation. It takes about 5-10 times longer to do a conversion. A 1MB picture which perhaps typically takes about 2 seconds to convert, will takes about 15 seconds to convert with auto-filter. So in most cases, you will want to leave this at its default, which is off.<br><br>

### `auto-limit`
```
Type: boolean
Default: true
Supported by: all
```
Limits the quality to be no more than that of the jpeg. The option is only relevant when converting jpegs to lossy webp. To be functional, webp-convert needs to be able to detect the quality of the jpeg, which requires ImageMagick or GraphicsMagick. Read about the option in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).

### `cwebp-command-line-options`
```
Type: string
Expand Down Expand Up @@ -69,13 +77,13 @@ Supported by: cwebp
```
If set, the converter will try the precompiled cwebp binary that are located in `src/Convert/Converters/Binaries`, for the current OS. The binaries are hash-checked before executed.

### `default-quality`
### `default-quality` (DEPRECATED)
```
Type: integer (0-100)
Default: 75 for jpegs and 85 for pngs
Supported by: all (cwebp, ewww, gd, ffmpeg, gmagick, graphicsmagick, imagick, imagemagick, vips)
```
Read about this option in the ["auto quality" section in the introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
This option has been deprecated. See why [here](https://github.com/rosell-dk/webp-convert/issues/281). It was used to determine the quality in case auto limiting was not available.<br><br>

### `encoding`
```
Expand Down Expand Up @@ -130,13 +138,13 @@ Supported by: cwebp, imagick, imagemagick and graphicsmagick
```
Reduce memory usage of lossy encoding at the cost of ~30% longer encoding time and marginally larger output size. Read more in [the docs](https://developers.google.com/speed/webp/docs/cwebp).<br><br>

### `max-quality`
### `max-quality` (DEPRECATED)
```
Type: integer (0-100)
Default: 85
Supported by: all (cwebp, ewww, ffmpeg, gd, gmagick, graphicsmagick, imagick, imagemagick, vips)
```
Read about this option in the ["auto quality" section in the introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
This option has been deprecated. See why [here](https://github.com/rosell-dk/webp-convert/issues/281)<br><br>

### `metadata`
```
Expand Down Expand Up @@ -181,11 +189,11 @@ Using a preset will set many of the other options to suit a particular type of s

### `quality`
```
Type: integer (0-100) | "auto"
Default: "auto" for jpegs and 85 for pngs
Type: integer (0-100) | "auto" ("auto" is now deprecated - use the "auto-limit" option instead)
Default: 75 for jpegs and 85 for pngs
Supported by: all (cwebp, ewww, gd, gmagick, graphicsmagick, imagick, imagemagick, vips, ffmpeg)
```
Quality for lossy encoding. Read about the "auto" option in the [introduction](https://github.com/rosell-dk/webp-convert/blob/master/docs/v2.0/converting/introduction-for-converting.md#auto-quality).<br><br>
Quality for lossy encoding.<br><br>

### `sharp-yuv`
```
Expand Down
60 changes: 49 additions & 11 deletions src/Convert/Converters/BaseTraits/AutoQualityTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,33 +92,71 @@ private function processQualityOption()
$options = $this->options;
$source = $this->source;

/*
Mapping from old options to new options:
quality: "auto", max-quality: 85, default-quality: 75
becomes: quality: 85, auto-limit: true
quality: 80
becomes: quality: 80, auto-limit: false
*/
$q = $options['quality'];
if ($q == 'auto') {
$q = $options['quality'] = $options['max-quality'];
$this->logLn(
'*Setting "quality" to "auto" is deprecated. ' .
'Instead, set "quality" to a number (0-100) and "auto-limit" to true. '
);
$this->logLn(
'*"quality" has been set to: ' . $options['max-quality'] . ' (took the value of "max-quality").*'
);
if (!$this->options2->getOptionById('auto-limit')->isValueExplicitlySet()) {
$options['auto-limit'] = true;
$this->logLn(
'*"auto-limit" has been set to: true."*'
);
} else {
$this->logLn(
'*PS: "auto-limit" is set to false, as it was set explicitly to false in the options."*'
);
}
}

if ($options['auto-limit']) {
if (($this->/** @scrutinizer ignore-call */getMimeTypeOfSource() == 'image/jpeg')) {
$this->logLn('Running auto-limit');
$this->logLn(
'Quality setting: ' . $q . '. '
);
$q = JpegQualityDetector::detectQualityOfJpg($source);
if (is_null($q)) {
$q = $options['default-quality'];
$q = $options['quality'];
$this->/** @scrutinizer ignore-call */logLn(
'Quality of source could not be established (Imagick or GraphicsMagick is required)' .
' - Using default instead (' . $options['default-quality'] . ').'
'Quality of source image could not be established (Imagick or GraphicsMagick is required). ' .
'Sorry, no auto-limit functionality for you. Using supplied quality (' . $q . ').'
);

$this->qualityCouldNotBeDetected = true;
} else {
if ($q > $options['max-quality']) {
$this->logLn(
'Quality of jpeg: ' . $q . '. '
);
if ($q < $options['quality']) {
$this->logLn(
'Quality of source is ' . $q . '. ' .
'This is higher than max-quality, so using max-quality instead (' .
$options['max-quality'] . ')'
'Auto-limit result: ' . $q . ' ' .
'(limiting applied).'
);
} else {
$this->logLn('Quality set to same as source: ' . $q);
$q = $options['quality'];
$this->logLn(
'Auto-limit result: ' . $q . ' ' .
'(no limiting needed this time).'
);
}
}
$q = min($q, $options['max-quality']);
} else {
//$q = $options['default-quality'];
$q = min($options['default-quality'], $options['max-quality']);
$this->logLn('Bypassing auto-limit (it is only active for jpegs)');
$this->logLn('Quality: ' . $q . '. ');
}
} else {
Expand All @@ -127,7 +165,7 @@ private function processQualityOption()
);
if (($this->getMimeTypeOfSource() == 'image/jpeg')) {
$this->logLn(
'Consider setting quality to "auto" instead. It is generally a better idea'
'Consider enabling "auto-limit" option. This will prevent unnecessary high quality'
);
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/Convert/Converters/BaseTraits/OptionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ abstract public function log($msg, $style = '');
abstract public function logLn($msg, $style = '');
abstract protected function getMimeTypeOfSource();

/** @var array Provided conversion options */
/** @var array Provided conversion options (array of simple objects)*/
public $providedOptions;

/** @var array Calculated conversion options (merge of default options and provided options)*/
Expand All @@ -54,19 +54,27 @@ abstract protected function getMimeTypeOfSource();
public function getGeneralOptions($imageType)
{
$isPng = ($imageType == 'png');

$defaultQualityOption = new IntegerOption('default-quality', ($isPng ? 85 : 75), 0, 100);
$defaultQualityOption->markDeprecated();

$maxQualityOption = new IntegerOption('max-quality', 85, 0, 100);
$maxQualityOption->markDeprecated();

return [
new IntegerOption('alpha-quality', 85, 0, 100),
new BooleanOption('auto-limit', true),
new BooleanOption('auto-filter', false),
new IntegerOption('default-quality', ($isPng ? 85 : 75), 0, 100),
$defaultQualityOption,
new StringOption('encoding', 'auto', ['lossy', 'lossless', 'auto']),
new BooleanOption('low-memory', false),
new BooleanOption('log-call-arguments', false),
new IntegerOption('max-quality', 85, 0, 100),
$maxQualityOption,
new MetadataOption('metadata', 'none'),
new IntegerOption('method', 6, 0, 6),
new IntegerOption('near-lossless', 60, 0, 100),
new StringOption('preset', 'none', ['none', 'default', 'photo', 'picture', 'drawing', 'icon', 'text']),
new QualityOption('quality', ($isPng ? 85 : 'auto')),
new QualityOption('quality', ($isPng ? 85 : 75)),
new IntegerOrNullOption('size-in-percentage', null, 0, 100),
new BooleanOption('sharp-yuv', true),
new BooleanOption('skip', false),
Expand Down
3 changes: 2 additions & 1 deletion tests/Convert/Converters/AbstractConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public function testDefaultOptions()

$defaultOptions = $exposer->getOptions();

$this->assertSame('auto', $defaultOptions['quality']);
//$this->assertSame('auto', $defaultOptions['quality']);
$this->assertSame(75, $defaultOptions['quality']);
$this->assertSame(85, $defaultOptions['max-quality']);
$this->assertSame(75, $defaultOptions['default-quality']);
$this->assertSame('none', $defaultOptions['metadata']);
Expand Down
Loading

0 comments on commit 1d162dd

Please sign in to comment.