Skip to content

Commit

Permalink
optimize batch generation of previews
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
icewind1991 committed Feb 16, 2020
1 parent f00a59b commit 636b4b7
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 15 deletions.
18 changes: 11 additions & 7 deletions lib/private/Preview/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =

// Get the max preview and infer the max preview sizes from that
$maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType, $previewVersion);
$maxPreviewImage = null; // only load the image when we need it
if ($maxPreview->getSize() === 0) {
$maxPreview->delete();
throw new NotFoundException('Max preview size 0, invalid!');
Expand Down Expand Up @@ -176,7 +177,11 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
try {
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
} 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) {
throw new NotFoundException();
Expand Down Expand Up @@ -388,9 +393,8 @@ private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHei
* @throws NotFoundException
* @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) {
$preview = $this->helper->getImage($maxPreview);

private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
$preview = $maxPreview;
if (!$preview->valid()) {
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
}
Expand All @@ -408,13 +412,13 @@ private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxP
$scaleH = $maxHeight / $widthR;
$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);
$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
$preview->crop($cropX, $cropY, $width, $height);
$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
} else {
$preview->resize(max($width, $height));
$preview = $maxPreview->resizeCopy(max($width, $height));
}


Expand Down
102 changes: 94 additions & 8 deletions lib/private/legacy/image.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
*
*/

use OCP\IImage;

/**
* Class for basic image manipulation
*/
Expand Down Expand Up @@ -844,6 +846,17 @@ private function imagecreatefrombmp($fileName) {
* @return bool
*/
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()) {
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
return false;
Expand All @@ -860,8 +873,7 @@ public function resize($maxSize) {
$newHeight = $maxSize;
}

$this->preciseResize((int)round($newWidth), (int)round($newHeight));
return true;
return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
}

/**
Expand All @@ -870,6 +882,19 @@ public function resize($maxSize) {
* @return 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()) {
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
return false;
Expand All @@ -895,9 +920,7 @@ public function preciseResize(int $width, int $height): bool {
imagedestroy($process);
return false;
}
imagedestroy($this->resource);
$this->resource = $process;
return true;
return $process;
}

/**
Expand Down Expand Up @@ -968,6 +991,22 @@ public function centerCrop($size = 0) {
* @return bool for success or failure
*/
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()) {
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
return false;
Expand All @@ -992,9 +1031,7 @@ public function crop(int $x, int $y, int $w, int $h): bool {
imagedestroy($process);
return false;
}
imagedestroy($this->resource);
$this->resource = $process;
return true;
return $process;
}

/**
Expand Down Expand Up @@ -1044,6 +1081,55 @@ public function scaleDownToFit($maxWidth, $maxHeight) {
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
*/
Expand Down
39 changes: 39 additions & 0 deletions lib/public/IImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,43 @@ public function fitIn($maxWidth, $maxHeight);
* @since 8.1.0
*/
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;
}

0 comments on commit 636b4b7

Please sign in to comment.