Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat(previews): Support in memory preview request
This allows callers to use the API without increasing the disk usage.

Example: blurhash generation, where we request a preview for all uploaded pictures, but don't want to necessarily store that preview.
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
artonge authored and backportbot[bot] committed May 6, 2025
commit 8e255bc6f55b5f58262d77597f6ec465a940fa3b
57 changes: 30 additions & 27 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 @@ -490,19 +489,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,8 +539,11 @@ 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) {
$file = $previewFolder->newFile($path, $preview->data());
} else {
return new InMemoryFile($path, $preview->data());
}
} catch (NotPermittedException $e) {
throw new NotFoundException();
}
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