Skip to content

Commit

Permalink
feature: add a setting to use 'imagecopyresampled' instead of 'imagec…
Browse files Browse the repository at this point in the history
…opyresized'

This function provides a better rendering after resizing with a tradoff of a higher CPU usage.
resampling is now used by default and can be changed using a simple setting before retrieving thumbnails.

The cache is not invalidated automatically by this option.
  • Loading branch information
ArthurHoaro committed Nov 24, 2022
1 parent 47675fc commit 777e774
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 16 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,35 @@ Usage:
$wt = $wt->crop(true);
$conf = [WebThumbnailer::CROP => true];
```

### Resize Mode

This setting choose whether to use `imagecopyresized` (RESIZE mode) or `imagecopyresampled` (RESAMPLE mode):

* `RESAMPLE`: higher CPI usage, with better resized image rendering.
* `RESIZE`: faster and lower CPU usage, but the resized image might not look as good.

By default, this library uses `RESAMPLE` setting since the setting was introduced.

Example:

|---------------------RESIZE---------------------|---------------------RESAMPLE---------------------|

![](https://user-images.githubusercontent.com/28786873/195634626-ec80e2ac-43f1-4f00-a507-8ba30dc5dda7.jpg)
![](https://user-images.githubusercontent.com/28786873/195634635-87f84476-e923-461c-accf-d3e5988e33a5.jpg)

Usage:

```php
// Resize
$wt = $wt->resize();
$conf = [WebThumbnailer::RESIZE_MODE => WebThumbnailer::RESIZE];

// Resample
$wt = $wt->resample();
$conf = [WebThumbnailer::RESIZE_MODE => WebThumbnailer::RESAMPLE];
```

### Miscellaneous

* **NOCACHE**: Force the thumbnail to be resolved and downloaded instead of using cache files.
Expand Down
12 changes: 10 additions & 2 deletions src/Application/Thumbnailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Thumbnailer
public function __construct(string $url, array $options, ?array $server)
{
ApplicationUtils::checkExtensionRequirements(['gd']);
ApplicationUtils::checkPHPVersion('5.6', PHP_VERSION);
ApplicationUtils::checkPHPVersion('7.1', PHP_VERSION);

$this->url = $url;
$this->server = $server;
Expand Down Expand Up @@ -128,6 +128,13 @@ protected function setOptions(array $options): void
$this->options[WebThumbnailer::DEBUG] = false;
}

// Resize mode, defaults to resample
if (isset($options[WebThumbnailer::RESIZE_MODE])) {
$this->options[WebThumbnailer::RESIZE_MODE] = $options[WebThumbnailer::RESIZE_MODE];
} else {
$this->options[WebThumbnailer::RESIZE_MODE] = WebThumbnailer::RESAMPLE;
}

// Image size
$this->setSizeOptions($options);
}
Expand Down Expand Up @@ -354,7 +361,8 @@ protected function thumbnailDownload(string $thumbUrl)
$thumbPath,
$this->options[WebThumbnailer::MAX_WIDTH],
$this->options[WebThumbnailer::MAX_HEIGHT],
$this->options[WebThumbnailer::CROP]
$this->options[WebThumbnailer::CROP],
$this->options[WebThumbnailer::RESIZE_MODE]
);

if (!is_file($thumbPath)) {
Expand Down
7 changes: 5 additions & 2 deletions src/Utils/ImageUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use WebThumbnailer\Exception\ImageConvertException;
use WebThumbnailer\Exception\NotAnImageException;
use WebThumbnailer\WebThumbnailer;

/**
* Util class to manipulate GD images.
Expand Down Expand Up @@ -33,7 +34,8 @@ public static function generateThumbnail(
string $target,
int $maxWidth,
int $maxHeight,
bool $crop = false
bool $crop = false,
string $resizeMode = WebThumbnailer::RESAMPLE
): void {
if (!touch($target)) {
throw new ImageConvertException('Target file is not writable.');
Expand Down Expand Up @@ -74,8 +76,9 @@ public static function generateThumbnail(
throw new ImageConvertException('Could not generate the thumbnail from source image.');
}

$resizeFunction = $resizeMode === WebThumbnailer::RESIZE ? 'imagecopyresized' : 'imagecopyresampled';
if (
!imagecopyresized(
!$resizeFunction(
$targetImg,
$sourceImg,
0,
Expand Down
39 changes: 39 additions & 0 deletions src/WebThumbnailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ class WebThumbnailer
/** Debug mode. Throw exceptions. */
public const DEBUG = 'DEBUG';

/** Setting to define resize mode */
public const RESIZE_MODE = 'RESIZE_MODE';

/** Resize mode: less CPU usage but could end up pixellized */
public const RESIZE = 'RESIZE';

/** Resample mode: more CPU usage but smoother rendering */
public const RESAMPLE = 'RESAMPLE';

/** @var int|null */
protected $maxWidth = null;

Expand Down Expand Up @@ -79,6 +88,9 @@ class WebThumbnailer
/** @var string|null */
protected $downloadMode = null;

/** @var string|null */
protected $resizeMode = null;

/**
* Get the thumbnail for the given URL>
*
Expand Down Expand Up @@ -106,6 +118,7 @@ public function thumbnail(string $url, array $options = [])
static::DOWNLOAD_TIMEOUT => $this->downloadTimeout,
static::DOWNLOAD_MAX_SIZE => $this->downloadMaxSize,
static::CROP => $this->crop,
static::RESIZE_MODE => $this->resizeMode,
$this->downloadMode
],
$options
Expand Down Expand Up @@ -262,4 +275,30 @@ public function modeHotlinkStrict(): self

return $this;
}

/**
* Apply resize mode during resizing:
* lower CPU usage but sometimes rougher rendering.
*
* @return WebThumbnailer $this
*/
public function resize(): self
{
$this->resizeMode = static::RESIZE;

return $this;
}

/**
* Apply resample mode during resizing:
* slightly more CPU usage but smoother rendering.
*
* @return WebThumbnailer $this
*/
public function resample(): self
{
$this->resizeMode = static::RESAMPLE;

return $this;
}
}
42 changes: 30 additions & 12 deletions tests/WebThumbnailerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,28 @@ public function testDirectImageWithoutExtension(): void
/**
* URL which contains an opengraph image.
*/
public function testOpenGraphImage(): void
public function testOpenGraphImageResample(): void
{
$image = 'default/le-monde-full.jpg';
$this->regenerate($image, true, [0, 0, 160, 80]);
$expected = self::$regenerated . $image;
$url = self::LOCAL_SERVER . 'default/le-monde.html';
$wt = new WebThumbnailer();
$thumb = $wt->resample()->thumbnail($url);
$this->assertFileEquals($expected, $thumb);
}

/**
* URL which contains an opengraph image.
*/
public function testOpenGraphImageResize(): void
{
$image = 'default/le-monde.jpg';
$this->regenerate($image);
$this->regenerate($image, false, [], 'imagecopyresized');
$expected = self::$regenerated . $image;
$url = self::LOCAL_SERVER . 'default/le-monde.html';
$wt = new WebThumbnailer();
$thumb = $wt->thumbnail($url);
$thumb = $wt->resize()->thumbnail($url);
$this->assertFileEquals($expected, $thumb);
}

Expand Down Expand Up @@ -243,11 +257,11 @@ public function testDownloadDirectImageResizeHeightCrop(): void
public function testDownloadDirectImageResizeWidthHeightCrop(): void
{
$image = 'default/image-crop-341-341.png';
$this->regenerate($image, true);
$this->regenerate($image, true, [], 'imagecopyresized');
$expected = self::$regenerated . $image;
$url = self::LOCAL_SERVER . 'default/image-crop.png';
$wt = new WebThumbnailer();
$wt = $wt->maxHeight(341)->maxWidth(341)->crop(true);
$wt = $wt->maxHeight(341)->maxWidth(341)->resize()->crop(true);
$thumb = $wt->thumbnail($url);
$this->assertEquals(base64_encode(file_get_contents($expected)), base64_encode(file_get_contents($thumb)));
$this->assertFileEquals($expected, $thumb);
Expand All @@ -260,11 +274,11 @@ public function testDownloadDirectImageResizeWidthHeightCrop(): void
public function testDownloadDirectImageResizeWidthHeightCropOverride(): void
{
$image = 'default/image-crop-120-160.png';
$this->regenerate($image, true);
$this->regenerate($image, true, [], 'imagecopyresized');
$expected = self::$regenerated . $image;
$url = self::LOCAL_SERVER . 'default/image-crop.png';
$wt = new WebThumbnailer();
$wt = $wt->maxHeight(341)->maxWidth(341)->crop(true);
$wt = $wt->maxHeight(341)->maxWidth(341)->crop(true)->resize();
$thumb = $wt->thumbnail(
$url,
[
Expand Down Expand Up @@ -336,8 +350,12 @@ public function testHotlinkOpenGraphJsonConfig(): void
*
* @throws \Exception couldn't create the image.
*/
public function regenerate(string $image, bool $crop = false, array $cropParameters = []): void
{
public function regenerate(
string $image,
bool $crop = false,
array $cropParameters = [],
string $resizeFunc = 'imagecopyresampled'
): void {
$targetFolder = dirname(self::$regenerated . $image);
if (! is_dir($targetFolder)) {
mkdir($targetFolder, 0755, true);
Expand All @@ -350,15 +368,15 @@ public function regenerate(string $image, bool $crop = false, array $cropParamet

$targetImg = imagecreatetruecolor($width, $height);
if (
!imagecopyresized(
!$resizeFunc(
$targetImg,
$sourceImg,
0,
0,
0,
0,
$width,
$height,
$cropParameters[2] ?? $width,
$cropParameters[3] ?? $height,
$width,
$height
)
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 777e774

Please sign in to comment.