Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions build/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2249,24 +2249,9 @@
</InvalidReturnStatement>
</file>
<file src="lib/private/Preview/Generator.php">
<InvalidArgument>
<code><![CDATA[$maxPreviewImage]]></code>
</InvalidArgument>
<LessSpecificReturnType>
<code><![CDATA[null|string]]></code>
</LessSpecificReturnType>
<MismatchingDocblockParamType>
<code><![CDATA[ISimpleFile]]></code>
</MismatchingDocblockParamType>
<UndefinedInterfaceMethod>
<code><![CDATA[height]]></code>
<code><![CDATA[height]]></code>
<code><![CDATA[preciseResizeCopy]]></code>
<code><![CDATA[resizeCopy]]></code>
<code><![CDATA[valid]]></code>
<code><![CDATA[width]]></code>
<code><![CDATA[width]]></code>
</UndefinedInterfaceMethod>
</file>
<file src="lib/private/Preview/ProviderV1Adapter.php">
<InvalidReturnStatement>
Expand Down
41 changes: 9 additions & 32 deletions lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use OCP\FilesMetadata\AMetadataEvent;
use OCP\FilesMetadata\Event\MetadataBackgroundEvent;
use OCP\FilesMetadata\Event\MetadataLiveEvent;
use OCP\IPreview;
use OCP\Lock\LockedException;

/**
Expand All @@ -27,11 +28,14 @@
* @template-implements IEventListener<AMetadataEvent>
*/
class GenerateBlurhashMetadata implements IEventListener {
private const RESIZE_BOXSIZE = 30;

private const COMPONENTS_X = 4;
private const COMPONENTS_Y = 3;

public function __construct(
private IPreview $preview,
) {
}

/**
* @throws NotPermittedException
* @throws GenericFileException
Expand Down Expand Up @@ -64,7 +68,9 @@ public function handle(Event $event): void {
return;
}

$image = $this->resizedImageFromFile($file);
$preview = $this->preview->getPreview($file, 64, 64, cacheResult: false);
$image = @imagecreatefromstring($preview->getContent());

if (!$image) {
return;
}
Expand All @@ -73,35 +79,6 @@ public function handle(Event $event): void {
->setEtag('blurhash', $currentEtag);
}

/**
* @param File $file
*
* @return GdImage|false
* @throws GenericFileException
* @throws NotPermittedException
* @throws LockedException
*/
private function resizedImageFromFile(File $file): GdImage|false {
$image = @imagecreatefromstring($file->getContent());
if ($image === false) {
return false;
}

$currX = imagesx($image);
$currY = imagesy($image);

if ($currX > $currY) {
$newX = self::RESIZE_BOXSIZE;
$newY = intval($currY * $newX / $currX);
} else {
$newY = self::RESIZE_BOXSIZE;
$newX = intval($currX * $newY / $currY);
}

$newImage = @imagescale($image, $newX, $newY);
return ($newImage !== false) ? $newImage : $image;
}

/**
* @param GdImage $image
*
Expand Down
63 changes: 32 additions & 31 deletions lib/private/Preview/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\InMemoryFile;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
Expand Down Expand Up @@ -43,17 +44,19 @@ public function __construct(
* The cache is searched first and if nothing usable was found then a preview is
* generated by one of the providers
*
* @param File $file
* @param int $width
* @param int $height
* @param bool $crop
* @param string $mode
* @param string|null $mimeType
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
public function getPreview(
File $file,
int $width = -1,
int $height = -1,
bool $crop = false,
string $mode = IPreview::MODE_FILL,
?string $mimeType = null,
bool $cacheResult = true,
): ISimpleFile {
$specification = [
'width' => $width,
'height' => $height,
Expand All @@ -78,23 +81,19 @@ public function getPreview(File $file, $width = -1, $height = -1, $crop = false,
'mode' => $mode,
'mimeType' => $mimeType,
]);


// since we only ask for one preview, and the generate method return the last one it created, it returns the one we want
return $this->generatePreviews($file, [$specification], $mimeType);
return $this->generatePreviews($file, [$specification], $mimeType, $cacheResult);
}

/**
* Generates previews of a file
*
* @param File $file
* @param non-empty-array $specifications
* @param string $mimeType
* @return ISimpleFile the last preview that was generated
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
public function generatePreviews(File $file, array $specifications, $mimeType = null) {
public function generatePreviews(File $file, array $specifications, ?string $mimeType = null, bool $cacheResult = true): ISimpleFile {
//Make sure that we can read the file
if (!$file->isReadable()) {
$this->logger->warning('Cannot read file: {path}, skipping preview generation.', ['path' => $file->getPath()]);
Expand Down Expand Up @@ -167,7 +166,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
}

$this->logger->warning('Cached preview not found for file {path}, generating a new preview.', ['path' => $file->getPath()]);
$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion, $cacheResult);
// New file, augment our array
$previewFiles[] = $preview;
}
Expand Down Expand Up @@ -351,11 +350,10 @@ private function generateProviderPreview(ISimpleFolder $previewFolder, File $fil

$path = $this->generatePath($preview->width(), $preview->height(), $crop, $max, $preview->dataMimeType(), $prefix);
try {
$file = $previewFolder->newFile($path);
if ($preview instanceof IStreamImage) {
$file->putContent($preview->resource());
return $previewFolder->newFile($path, $preview->resource());
} else {
$file->putContent($preview->data());
return $previewFolder->newFile($path, $preview->data());
}
} catch (NotPermittedException $e) {
throw new NotFoundException();
Expand Down Expand Up @@ -490,19 +488,20 @@ private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHei
}

/**
* @param ISimpleFolder $previewFolder
* @param ISimpleFile $maxPreview
* @param int $width
* @param int $height
* @param bool $crop
* @param int $maxWidth
* @param int $maxHeight
* @param string $prefix
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
private function generatePreview(
ISimpleFolder $previewFolder,
IImage $maxPreview,
int $width,
int $height,
bool $crop,
int $maxWidth,
int $maxHeight,
string $prefix,
bool $cacheResult,
): ISimpleFile {
$preview = $maxPreview;
if (!$preview->valid()) {
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
Expand Down Expand Up @@ -539,12 +538,14 @@ private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPrevie

$path = $this->generatePath($width, $height, $crop, false, $preview->dataMimeType(), $prefix);
try {
$file = $previewFolder->newFile($path);
$file->putContent($preview->data());
if ($cacheResult) {
return $previewFolder->newFile($path, $preview->data());
} else {
return new InMemoryFile($path, $preview->data());
}
} catch (NotPermittedException $e) {
throw new NotFoundException();
}

return $file;
}

Expand Down
29 changes: 10 additions & 19 deletions lib/private/PreviewManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,29 +145,20 @@ private function getGenerator(): Generator {
return $this->generator;
}

/**
* Returns a preview of a file
*
* The cache is searched first and if nothing usable was found then a preview is
* generated by one of the providers
*
* @param File $file
* @param int $width
* @param int $height
* @param bool $crop
* @param string $mode
* @param string $mimeType
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
* @since 11.0.0 - \InvalidArgumentException was added in 12.0.0
*/
public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
public function getPreview(
File $file,
$width = -1,
$height = -1,
$crop = false,
$mode = IPreview::MODE_FILL,
$mimeType = null,
bool $cacheResult = true,
): ISimpleFile {
$this->throwIfPreviewsDisabled();
$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
try {
$preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType);
$preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
} finally {
Generator::unguardWithSemaphore($sem);
}
Expand Down
4 changes: 3 additions & 1 deletion lib/public/IPreview.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ public function hasProviders();
* @param bool $crop
* @param string $mode
* @param string $mimeType To force a given mimetype for the file (files_versions needs this)
* @param bool $cacheResult Whether or not to cache the preview on the filesystem. Default to true. Can be useful to set to false to limit the amount of stored previews.
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
* @since 11.0.0 - \InvalidArgumentException was added in 12.0.0
* @since 32.0.0 - getPreview($cacheResult) added the $cacheResult argument to the signature
*/
public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null);
public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null, bool $cacheResult = true);

/**
* Returns true if the passed mime type is supported
Expand Down
32 changes: 10 additions & 22 deletions tests/lib/Preview/GeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@
use Psr\Log\LoggerInterface;

class GeneratorTest extends \Test\TestCase {
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
/** @var IConfig&\PHPUnit\Framework\MockObject\MockObject */
private $config;

/** @var IPreview|\PHPUnit\Framework\MockObject\MockObject */
/** @var IPreview&\PHPUnit\Framework\MockObject\MockObject */
private $previewManager;

/** @var IAppData|\PHPUnit\Framework\MockObject\MockObject */
/** @var IAppData&\PHPUnit\Framework\MockObject\MockObject */
private $appData;

/** @var GeneratorHelper|\PHPUnit\Framework\MockObject\MockObject */
/** @var GeneratorHelper&\PHPUnit\Framework\MockObject\MockObject */
private $helper;

/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
/** @var IEventDispatcher&\PHPUnit\Framework\MockObject\MockObject */
private $eventDispatcher;

/** @var Generator */
private $generator;

private LoggerInterface|\PHPUnit\Framework\MockObject\MockObject $logger;
private LoggerInterface&\PHPUnit\Framework\MockObject\MockObject $logger;

protected function setUp(): void {
parent::setUp();
Expand Down Expand Up @@ -196,18 +196,10 @@ public function testGetNewPreview(): void {
$previewFolder->method('getDirectoryListing')
->willReturn([]);
$previewFolder->method('newFile')
->willReturnCallback(function ($filename) use ($maxPreview, $previewFile) {
if ($filename === '2048-2048-max.png') {
return $maxPreview;
} elseif ($filename === '256-256.png') {
return $previewFile;
}
$this->fail('Unexpected file');
});

$maxPreview->expects($this->once())
->method('putContent')
->with($this->equalTo('my data'));
->willReturnMap([
['2048-2048-max.png', 'my data', $maxPreview],
['256-256.png', 'my resized data', $previewFile],
]);

$previewFolder->method('getFile')
->with($this->equalTo('256-256.png'))
Expand All @@ -218,10 +210,6 @@ public function testGetNewPreview(): void {
->with($this->equalTo($maxPreview))
->willReturn($image);

$previewFile->expects($this->once())
->method('putContent')
->with('my resized data');

$this->eventDispatcher->expects($this->once())
->method('dispatchTyped')
->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL, null));
Expand Down
Loading