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

FEATURE: Only output existing images and allow upscaling #70

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 0 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
php-versions: ['8.0', '8.1']
neos-versions: ['8.3']
include:
- php-versions: '7.3'
neos-versions: '7.3'
- php-versions: '7.4'
neos-versions: '7.3'
- php-versions: '8.0'
Expand Down
28 changes: 1 addition & 27 deletions Classes/Domain/AbstractImageSource.php
manuelmeister marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Neos\Eel\ProtectedContextAwareInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\Utility\Arrays;
use Psr\Log\LoggerInterface;
use Sitegeist\Kaleidoscope\EelHelpers\ImageSourceHelperInterface;

Expand Down Expand Up @@ -218,39 +217,14 @@ public function withVariantPreset(string $presetIdentifier, string $presetVarian
}

/**
* Render sourceset Attribute for various media descriptors.
* Render sourceset Attribute non-scalable media.
*
* @param mixed $mediaDescriptors
*
* @return string
*/
public function srcset($mediaDescriptors): string
{
if ($this instanceof ScalableImageSourceInterface) {
$srcsetArray = [];

if (is_array($mediaDescriptors) || $mediaDescriptors instanceof \Traversable) {
$descriptors = $mediaDescriptors;
} else {
$descriptors = Arrays::trimExplode(',', (string) $mediaDescriptors);
}

foreach ($descriptors as $descriptor) {
if (preg_match('/^(?<width>[0-9]+)w$/u', $descriptor, $matches)) {
$width = (int) $matches['width'];
$scaleFactor = $width / $this->width();
$scaled = $this->scale($scaleFactor);
$srcsetArray[] = $scaled->src() . ' ' . $width . 'w';
} elseif (preg_match('/^(?<factor>[0-9\\.]+)x$/u', $descriptor, $matches)) {
$factor = (float) $matches['factor'];
$scaled = $this->scale($factor);
$srcsetArray[] = $scaled->src() . ' ' . $factor . 'x';
}
}

return implode(', ', $srcsetArray);
}

return $this->src();
}

Expand Down
97 changes: 91 additions & 6 deletions Classes/Domain/AbstractScalableImageSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
use Imagine\Image\Box;
use Imagine\Image\ImagineInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\Media\Domain\Model\Adjustment\CropImageAdjustment;
use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface;
use Neos\Media\Domain\Model\Adjustment\ResizeImageAdjustment;
use Neos\Media\Domain\ValueObject\Configuration\Adjustment;
use Neos\Media\Domain\ValueObject\Configuration\VariantPreset;
use Neos\Utility\ObjectAccess;
use Neos\Utility\Arrays;
use Sitegeist\Kaleidoscope\EelHelpers\ScalableImageSourceHelperInterface;

abstract class AbstractScalableImageSource extends AbstractImageSource implements ScalableImageSourceInterface, ScalableImageSourceHelperInterface
Expand All @@ -38,9 +40,9 @@ abstract class AbstractScalableImageSource extends AbstractImageSource implement
* @param int|null $targetWidth
* @param bool $preserveAspect
*
* @return ImageSourceInterface
* @return ScalableImageSourceInterface
*/
public function withWidth(int $targetWidth = null, bool $preserveAspect = false): ImageSourceInterface
public function withWidth(int $targetWidth = null, bool $preserveAspect = false): ScalableImageSourceInterface
{
$newSource = clone $this;
$newSource->targetWidth = $targetWidth;
Expand All @@ -60,9 +62,9 @@ public function withWidth(int $targetWidth = null, bool $preserveAspect = false)
* @param int|null $targetHeight
* @param bool $preserveAspect
*
* @return ImageSourceInterface
* @return ScalableImageSourceInterface
*/
public function withHeight(int $targetHeight = null, bool $preserveAspect = false): ImageSourceInterface
public function withHeight(int $targetHeight = null, bool $preserveAspect = false): ScalableImageSourceInterface
{
$newSource = clone $this;
$newSource->targetHeight = $targetHeight;
Expand All @@ -78,12 +80,28 @@ public function withHeight(int $targetHeight = null, bool $preserveAspect = fals
return $newSource;
}

/**
* @param int $targetWidth
* @param int $targetHeight
*
* @return ScalableImageSourceInterface
*/
public function withDimensions(int $targetWidth, int $targetHeight): ScalableImageSourceInterface
{
$newSource = clone $this;
$newSource->targetWidth = $targetWidth;
$newSource->targetHeight = $targetHeight;

return $newSource;
}


/**
* @param float $factor
*
* @return ImageSourceInterface
* @return ScalableImageSourceInterface
*/
public function scale(float $factor): ImageSourceInterface
public function scale(float $factor): ScalableImageSourceInterface
{
$scaledHelper = clone $this;

Expand Down Expand Up @@ -213,4 +231,71 @@ protected function createAdjustment(Adjustment $adjustmentConfiguration): ImageA

return $adjustment;
}

/**
* Render srcset Attribute for various media descriptors.
*
* If upscaling is not allowed and the width is greater than the base width,
* use the base width.
*
* @param $mediaDescriptors
*
* @return string
*/
public function srcset($mediaDescriptors): string
{
$srcsetArray = [];

if (is_array($mediaDescriptors) || $mediaDescriptors instanceof \Traversable) {
$descriptors = $mediaDescriptors;
} else {
$descriptors = Arrays::trimExplode(',', (string)$mediaDescriptors);
}

$srcsetType = null;
$maxScaleFactor = min($this->baseWidth / $this->width(), $this->baseHeight / $this->height());

foreach ($descriptors as $descriptor) {
$hasDescriptor = preg_match('/^(?<width>[0-9]+)w$|^(?<factor>[0-9\\.]+)x$/u', $descriptor, $matches, PREG_UNMATCHED_AS_NULL);

if (!$hasDescriptor) {
$this->logger->warning(sprintf('Invalid media descriptor "%s". Missing type "x" or "w"', $descriptor), LogEnvironment::fromMethodName(__METHOD__));
continue;
}

if (!$srcsetType) {
$srcsetType = isset($matches['width']) ? 'width' : 'factor';
} elseif (($srcsetType === 'width' && isset($matches['factor'])) || ($srcsetType === 'factor' && isset($matches['width']))) {
$this->logger->warning(sprintf('Mixed media descriptors are not valid: [%s]', implode(', ', is_array($descriptors) ? $descriptors : iterator_to_array($descriptors))), LogEnvironment::fromMethodName(__METHOD__));
continue;
}

if ($srcsetType === 'width') {
$width = (int)$matches['width'];
$scaleFactor = $width / $this->width();
if (!$this->supportsUpscaling() && ($width / $this->baseWidth > 1)) {
$srcsetArray[] = $this->src() . ' ' . $this->baseWidth . 'w';
} else {
$scaled = $this->scale($scaleFactor);
$srcsetArray[] = $scaled->src() . ' ' . $width . 'w';
}
} elseif ($srcsetType === 'factor') {
$factor = (float)$matches['factor'];
if (
!$this->supportsUpscaling() && (
($this->targetHeight && ($maxScaleFactor < $factor)) ||
($this->targetWidth && ($maxScaleFactor < $factor))
)
) {
$scaled = $this->scale($maxScaleFactor);
$srcsetArray[] = $scaled->src() . ' ' . $maxScaleFactor . 'x';
} else {
$scaled = $this->scale($factor);
$srcsetArray[] = $scaled->src() . ' ' . $factor . 'x';
}
}
}

return implode(', ', array_unique($srcsetArray));
}
}
9 changes: 7 additions & 2 deletions Classes/Domain/AssetImageSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public function __construct(ImageInterface $asset, ?string $title = null, ?strin
$this->baseHeight = $this->asset->getHeight();
}

public function supportsUpscaling(): bool
{
return false;
}

/**
* Use the variant generated from the given variant preset in this image source.
*
Expand Down Expand Up @@ -128,7 +133,7 @@ public function src(): string

$async = $this->request ? $this->async : false;
$allowCropping = true;
$allowUpScaling = false;
$allowUpScaling = $this->supportsUpscaling();
$thumbnailConfiguration = new ThumbnailConfiguration(
$width,
$width,
Expand Down Expand Up @@ -168,7 +173,7 @@ public function dataSrc(): string

$async = false;
$allowCropping = true;
$allowUpScaling = false;
$allowUpScaling = $this->supportsUpscaling();
$thumbnailConfiguration = new ThumbnailConfiguration(
$width,
$width,
Expand Down
13 changes: 12 additions & 1 deletion Classes/Domain/DummyImageSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class DummyImageSource extends AbstractScalableImageSource
*/
protected $baseUri;

/**
* @var bool
*/
private $allowUpScaling;

/**
* @param string $baseUri
* @param string|null $title
Expand All @@ -45,7 +50,7 @@ class DummyImageSource extends AbstractScalableImageSource
* @param string|null $foregroundColor
* @param string|null $text
*/
public function __construct(string $baseUri, ?string $title = null, ?string $alt = null, ?int $baseWidth = null, ?int $baseHeight = null, ?string $backgroundColor = null, ?string $foregroundColor = null, ?string $text = null)
public function __construct(string $baseUri, ?string $title = null, ?string $alt = null, ?int $baseWidth = null, ?int $baseHeight = null, ?string $backgroundColor = null, ?string $foregroundColor = null, ?string $text = null, bool $allowUpScaling = true)
{
parent::__construct($title, $alt);
$this->baseUri = $baseUri;
Expand All @@ -54,6 +59,12 @@ public function __construct(string $baseUri, ?string $title = null, ?string $alt
$this->backgroundColor = $backgroundColor ?? '999';
$this->foregroundColor = $foregroundColor ?? 'fff';
$this->text = $text ?? '';
$this->allowUpScaling = $allowUpScaling;
}

public function supportsUpscaling(): bool
{
return $this->allowUpScaling;
}

/**
Expand Down
1 change: 1 addition & 0 deletions Classes/Domain/ScalableImageSourceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@

interface ScalableImageSourceInterface extends ImageSourceInterface
{
public function supportsUpscaling(): bool;
public function scale(float $factor): ImageSourceInterface;
}
Loading
Loading