Skip to content
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

Enable timeout setting for the optimize method #187

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 15 additions & 6 deletions docs/image-manipulations/optimizing-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ weight: 3

## Requirements

Optimization of images is done by the underlying [spatie/image-optimizer](https://github.com/spatie/image-optimizer). It assumes that there are a few optimization tools, such as [JpegOptim](http://freecode.com/projects/jpegoptim) an [Pngquant](https://pngquant.org/) present on your system. For more info, check out [the relevant docs](https://github.com/spatie/image-optimizer#optimization-tools).
Optimization of images is done by the underlying [spatie/image-optimizer](https://github.com/spatie/image-optimizer) package. It assumes that there are a few optimization tools, such as [JpegOptim](http://freecode.com/projects/jpegoptim) an [Pngquant](https://pngquant.org/) present on your system. For more info, check out [the relevant docs](https://github.com/spatie/image-optimizer#optimization-tools).

## How to use

Expand All @@ -28,17 +28,26 @@ No matter where or how many times you call `optimize` in you chain, it will alwa

## Customizing the optimization

To optimization of images is done by the underlying [spatie/image-optimizer](https://github.com/spatie/image-optimizer) package. You can pass your own customized chains as array. The keys should be fully qualified class names of optimizers and the values the options that they should get. Here's an example
You are able to customize the optimization by passing an options array to the `optimize` method:
- `'timeout'` settings key lets you to set a custom timeout in seconds other than the default 60s. Adjusting this setting may be inevitable while working with large images (see e.g. [#187](https://github.com/spatie/image/pull/187))
- `'optimizers'` settings key lets you to pass your own customized chain of optimizers as an array. The keys should be fully qualified class names of optimizers and the values should be the options that they should get

Here's an example:

```php
Image::load('example.jpg')
->optimize([Jpegoptim::class => [
'--all-progressive',
]])
->optimize([
'timeout' => 120,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of adding a key in the array, let's add a dedicated parameter to specify timeout.

So this would use default timeout.

php
Image::load('example.jpg')
     ->optimize([
         'optimizers' => [
             Jpegoptim::class => [
                 '--all-progressive',
             ],
         ],
     ])

and this is how you would use a custom timeout:

Image::load('example.jpg')
     ->optimize([
         'optimizers' => [
             Jpegoptim::class => [
                 '--all-progressive',
             ],
         ],
     ], timeout: 120)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @freekmurze 👋 Thanks for your feedback! I've updated the PR adding the $timeout parameter.

It seems that the only option I had to implement this was to reuse that array key. It's being added under the hood when the $timeout parameter is being passed:

    if ($timeout !== null) {
        $optimizationOptions['timeout'] = $timeout;
    }

The optimization options are always passed to the underlying layers with JSON serialization/deserialization:

    return $this->addManipulation('optimize', json_encode($optimizationOptions));

That's why only a single array is available for any configuration.

Moreover, in a Laravel project with the spatie/laravel-medialibrary one might want to be able to configure a timeout for optimizers. This can be achieved with the help of the image_optimizers settings key in the config/media-library.php adding e.g. 'timeout' => 120 to the array:

    'image_optimizers' => [
        'optimizers' => [
            Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [
                '-m85',
                // ...
            ],
        ],
        'timeout' => 120,
    ],

So I think the only possible way is to have both options available.

'optimizers' => [
Jpegoptim::class => [
'--all-progressive',
],
],
])
->save();
```

If you need more control over the optimizer chain, you can still pass your own instance of `OptimizerChain`. It can be especially useful if you need to set a custom timeout or a custom binary path. You may not have enough privileges to install the necessary binaries on your server but you can still upload some [precompiled binaries](https://github.com/imagemin?q=bin&type=&language=).
If you need more control over the optimizer chain, you can still pass your own instance of `OptimizerChain`. It can be especially useful if you need to set a custom binary path. You may not have enough privileges to install the necessary binaries on your server but you can still upload some [precompiled binaries](https://github.com/imagemin?q=bin&type=&language=).

```php
$optimizer = new OptimizerChain();
Expand Down
10 changes: 8 additions & 2 deletions src/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,10 @@ protected function performOptimization($path, array $optimizerChainConfiguration
$optimizerChain = $this->optimizerChain ?? OptimizerChainFactory::create();

if (count($optimizerChainConfiguration)) {
$optimizersOptions = isset($optimizerChainConfiguration['optimizers'])
? $optimizerChainConfiguration['optimizers']
: $optimizerChainConfiguration;
$existingOptimizers = $optimizerChain->getOptimizers();

$optimizers = array_map(function (array $optimizerOptions, string $optimizerClassName) use ($existingOptimizers) {
$optimizer = array_values(array_filter($existingOptimizers, function ($optimizer) use ($optimizerClassName) {
return $optimizer::class === $optimizerClassName;
Expand All @@ -150,9 +152,13 @@ protected function performOptimization($path, array $optimizerChainConfiguration
$optimizer = isset($optimizer[0]) && $optimizer[0] instanceof BaseOptimizer ? $optimizer[0] : new $optimizerClassName();

return $optimizer->setOptions($optimizerOptions)->setBinaryPath($optimizer->binaryPath);
}, $optimizerChainConfiguration, array_keys($optimizerChainConfiguration));
}, $optimizersOptions, array_keys($optimizersOptions));

$optimizerChain->setOptimizers($optimizers);

if (isset($optimizerChainConfiguration['timeout'])) {
$optimizerChain->setTimeout($optimizerChainConfiguration['timeout']);
}
}

$optimizerChain->optimize($path);
Expand Down
48 changes: 42 additions & 6 deletions tests/Manipulations/OptimizeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@
it('can optimize an image with the given optimization options', function () {
$targetFile = $this->tempDir->path('optimized.jpg');

Image::load(getTestFile('test.jpg'))
->optimize([
'optimizers' => [
Jpegoptim::class => [
'--all-progressive',
],
],
])
->save($targetFile);

expect($targetFile)->toBeFile();
});

it('can optimize an image with options format backward compatibility', function () {
$targetFile = $this->tempDir->path('optimized.jpg');

Image::load(getTestFile('test.jpg'))
->optimize([Jpegoptim::class => [
'--all-progressive',
Expand All @@ -46,12 +62,32 @@
Image::load(getTestFile('test.jpg'))
->setOptimizeChain(OptimizerChainFactory::create())
->optimize([
Pngquant::class => [
'--force',
],
Jpegoptim::class => [
'--all-progressive',
],
'optimizers' => [
Pngquant::class => [
'--force',
],
Jpegoptim::class => [
'--all-progressive',
],
],
])
->save($targetFile);

expect($targetFile)->toBeFile();
});

it('can optimize an image specifying a desired timeout', function () {
$targetFile = $this->tempDir->path('optimized.jpg');

Image::load(getTestFile('test.jpg'))
->setOptimizeChain(OptimizerChainFactory::create())
->optimize([
'timeout' => 120,
'optimizers' => [
Jpegoptim::class => [
'--all-progressive',
],
],
])
->save($targetFile);

Expand Down