optimize batch generation of previews
by allowing the generation of multiple previews at once we save on having to find, open and decode the max-preview for every preview of the same file the main use case for this is the preview generator app (pr for that comming next) in my local testing this saves about 25% of time when using the preview generator app Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
5cd12cd7c3
commit
7d386872e5
|
@ -138,6 +138,7 @@ class Generator {
|
||||||
|
|
||||||
// Get the max preview and infer the max preview sizes from that
|
// Get the max preview and infer the max preview sizes from that
|
||||||
$maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType, $previewVersion);
|
$maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType, $previewVersion);
|
||||||
|
$maxPreviewImage = null; // only load the image when we need it
|
||||||
if ($maxPreview->getSize() === 0) {
|
if ($maxPreview->getSize() === 0) {
|
||||||
$maxPreview->delete();
|
$maxPreview->delete();
|
||||||
throw new NotFoundException('Max preview size 0, invalid!');
|
throw new NotFoundException('Max preview size 0, invalid!');
|
||||||
|
@ -174,7 +175,11 @@ class Generator {
|
||||||
try {
|
try {
|
||||||
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
|
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
$preview = $this->generatePreview($previewFolder, $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
|
if ($maxPreviewImage === null) {
|
||||||
|
$maxPreviewImage = $this->helper->getImage($maxPreview);
|
||||||
|
}
|
||||||
|
|
||||||
|
$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
|
||||||
}
|
}
|
||||||
} catch (\InvalidArgumentException $e) {
|
} catch (\InvalidArgumentException $e) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
@ -386,9 +391,8 @@ class Generator {
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
|
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
|
||||||
*/
|
*/
|
||||||
private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
|
private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
|
||||||
$preview = $this->helper->getImage($maxPreview);
|
$preview = $maxPreview;
|
||||||
|
|
||||||
if (!$preview->valid()) {
|
if (!$preview->valid()) {
|
||||||
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
|
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
|
||||||
}
|
}
|
||||||
|
@ -406,13 +410,13 @@ class Generator {
|
||||||
$scaleH = $maxHeight / $widthR;
|
$scaleH = $maxHeight / $widthR;
|
||||||
$scaleW = $width;
|
$scaleW = $width;
|
||||||
}
|
}
|
||||||
$preview->preciseResize((int)round($scaleW), (int)round($scaleH));
|
$preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
|
||||||
}
|
}
|
||||||
$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
|
$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
|
||||||
$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
|
$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
|
||||||
$preview->crop($cropX, $cropY, $width, $height);
|
$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
|
||||||
} else {
|
} else {
|
||||||
$preview->resize(max($width, $height));
|
$preview = $maxPreview->resizeCopy(max($width, $height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use OCP\IImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for basic image manipulation
|
* Class for basic image manipulation
|
||||||
*/
|
*/
|
||||||
|
@ -845,6 +847,17 @@ class OC_Image implements \OCP\IImage {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function resize($maxSize) {
|
public function resize($maxSize) {
|
||||||
|
$result = $this->resizeNew($maxSize);
|
||||||
|
imagedestroy($this->resource);
|
||||||
|
$this->resource = $result;
|
||||||
|
return is_resource($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $maxSize
|
||||||
|
* @return resource | bool
|
||||||
|
*/
|
||||||
|
private function resizeNew($maxSize) {
|
||||||
if (!$this->valid()) {
|
if (!$this->valid()) {
|
||||||
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
||||||
return false;
|
return false;
|
||||||
|
@ -861,8 +874,7 @@ class OC_Image implements \OCP\IImage {
|
||||||
$newHeight = $maxSize;
|
$newHeight = $maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->preciseResize((int)round($newWidth), (int)round($newHeight));
|
return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -871,6 +883,19 @@ class OC_Image implements \OCP\IImage {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function preciseResize(int $width, int $height): bool {
|
public function preciseResize(int $width, int $height): bool {
|
||||||
|
$result = $this->preciseResizeNew($width, $height);
|
||||||
|
imagedestroy($this->resource);
|
||||||
|
$this->resource = $result;
|
||||||
|
return is_resource($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $width
|
||||||
|
* @param int $height
|
||||||
|
* @return resource | bool
|
||||||
|
*/
|
||||||
|
public function preciseResizeNew(int $width, int $height) {
|
||||||
if (!$this->valid()) {
|
if (!$this->valid()) {
|
||||||
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
||||||
return false;
|
return false;
|
||||||
|
@ -896,9 +921,7 @@ class OC_Image implements \OCP\IImage {
|
||||||
imagedestroy($process);
|
imagedestroy($process);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
imagedestroy($this->resource);
|
return $process;
|
||||||
$this->resource = $process;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -969,6 +992,22 @@ class OC_Image implements \OCP\IImage {
|
||||||
* @return bool for success or failure
|
* @return bool for success or failure
|
||||||
*/
|
*/
|
||||||
public function crop(int $x, int $y, int $w, int $h): bool {
|
public function crop(int $x, int $y, int $w, int $h): bool {
|
||||||
|
$result = $this->cropNew($x, $y, $w, $h);
|
||||||
|
imagedestroy($this->resource);
|
||||||
|
$this->resource = $result;
|
||||||
|
return is_resource($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crops the image from point $x$y with dimension $wx$h.
|
||||||
|
*
|
||||||
|
* @param int $x Horizontal position
|
||||||
|
* @param int $y Vertical position
|
||||||
|
* @param int $w Width
|
||||||
|
* @param int $h Height
|
||||||
|
* @return resource | bool
|
||||||
|
*/
|
||||||
|
public function cropNew(int $x, int $y, int $w, int $h) {
|
||||||
if (!$this->valid()) {
|
if (!$this->valid()) {
|
||||||
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
|
||||||
return false;
|
return false;
|
||||||
|
@ -993,9 +1032,7 @@ class OC_Image implements \OCP\IImage {
|
||||||
imagedestroy($process);
|
imagedestroy($process);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
imagedestroy($this->resource);
|
return $process;
|
||||||
$this->resource = $process;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1045,6 +1082,55 @@ class OC_Image implements \OCP\IImage {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function copy(): IImage {
|
||||||
|
$image = new OC_Image(null, $this->logger, $this->config);
|
||||||
|
$image->resource = imagecreatetruecolor($this->width(), $this->height());
|
||||||
|
imagecopy(
|
||||||
|
$image->resource(),
|
||||||
|
$this->resource(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
$this->width(),
|
||||||
|
$this->height()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cropCopy(int $x, int $y, int $w, int $h): IImage {
|
||||||
|
$image = new OC_Image(null, $this->logger, $this->config);
|
||||||
|
$image->resource = $this->cropNew($x, $y, $w, $h);
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preciseResizeCopy(int $width, int $height): IImage {
|
||||||
|
$image = new OC_Image(null, $this->logger, $this->config);
|
||||||
|
$image->resource = $this->preciseResizeNew($width, $height);
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resizeCopy(int $maxSize): IImage {
|
||||||
|
$image = new OC_Image(null, $this->logger, $this->config);
|
||||||
|
$image->resource = $this->resizeNew($maxSize);
|
||||||
|
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes the image preserving ratio, returning a new copy
|
||||||
|
*
|
||||||
|
* @param integer $maxSize The maximum size of either the width or height.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function copyResize($maxSize): IImage {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the current image and resets the object
|
* Destroys the current image and resets the object
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -190,4 +190,43 @@ interface IImage {
|
||||||
* @since 8.1.0
|
* @since 8.1.0
|
||||||
*/
|
*/
|
||||||
public function scaleDownToFit($maxWidth, $maxHeight);
|
public function scaleDownToFit($maxWidth, $maxHeight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a copy of this image
|
||||||
|
*
|
||||||
|
* @return IImage
|
||||||
|
* @since 19.0.0
|
||||||
|
*/
|
||||||
|
public function copy(): IImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a new cropped copy of this image
|
||||||
|
*
|
||||||
|
* @param int $x Horizontal position
|
||||||
|
* @param int $y Vertical position
|
||||||
|
* @param int $w Width
|
||||||
|
* @param int $h Height
|
||||||
|
* @return IImage
|
||||||
|
* @since 19.0.0
|
||||||
|
*/
|
||||||
|
public function cropCopy(int $x, int $y, int $w, int $h): IImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a new resized copy of this image
|
||||||
|
*
|
||||||
|
* @param int $width
|
||||||
|
* @param int $height
|
||||||
|
* @return IImage
|
||||||
|
* @since 19.0.0
|
||||||
|
*/
|
||||||
|
public function preciseResizeCopy(int $width, int $height): IImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a new resized copy of this image
|
||||||
|
*
|
||||||
|
* @param integer $maxSize The maximum size of either the width or height.
|
||||||
|
* @return IImage
|
||||||
|
* @since 19.0.0
|
||||||
|
*/
|
||||||
|
public function resizeCopy(int $maxSize): IImage;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue