Skip to content

Commit 636b4b7

Browse files
committed
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>
1 parent f00a59b commit 636b4b7

File tree

3 files changed

+144
-15
lines changed

3 files changed

+144
-15
lines changed

lib/private/Preview/Generator.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
140140

141141
// Get the max preview and infer the max preview sizes from that
142142
$maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType, $previewVersion);
143+
$maxPreviewImage = null; // only load the image when we need it
143144
if ($maxPreview->getSize() === 0) {
144145
$maxPreview->delete();
145146
throw new NotFoundException('Max preview size 0, invalid!');
@@ -176,7 +177,11 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
176177
try {
177178
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
178179
} catch (NotFoundException $e) {
179-
$preview = $this->generatePreview($previewFolder, $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
180+
if ($maxPreviewImage === null) {
181+
$maxPreviewImage = $this->helper->getImage($maxPreview);
182+
}
183+
184+
$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
180185
}
181186
} catch (\InvalidArgumentException $e) {
182187
throw new NotFoundException();
@@ -388,9 +393,8 @@ private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHei
388393
* @throws NotFoundException
389394
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
390395
*/
391-
private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
392-
$preview = $this->helper->getImage($maxPreview);
393-
396+
private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
397+
$preview = $maxPreview;
394398
if (!$preview->valid()) {
395399
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
396400
}
@@ -408,13 +412,13 @@ private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxP
408412
$scaleH = $maxHeight / $widthR;
409413
$scaleW = $width;
410414
}
411-
$preview->preciseResize((int)round($scaleW), (int)round($scaleH));
415+
$preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
412416
}
413417
$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
414418
$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
415-
$preview->crop($cropX, $cropY, $width, $height);
419+
$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
416420
} else {
417-
$preview->resize(max($width, $height));
421+
$preview = $maxPreview->resizeCopy(max($width, $height));
418422
}
419423

420424

lib/private/legacy/image.php

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
*
3939
*/
4040

41+
use OCP\IImage;
42+
4143
/**
4244
* Class for basic image manipulation
4345
*/
@@ -844,6 +846,17 @@ private function imagecreatefrombmp($fileName) {
844846
* @return bool
845847
*/
846848
public function resize($maxSize) {
849+
$result = $this->resizeNew($maxSize);
850+
imagedestroy($this->resource);
851+
$this->resource = $result;
852+
return is_resource($result);
853+
}
854+
855+
/**
856+
* @param $maxSize
857+
* @return resource | bool
858+
*/
859+
private function resizeNew($maxSize) {
847860
if (!$this->valid()) {
848861
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
849862
return false;
@@ -860,8 +873,7 @@ public function resize($maxSize) {
860873
$newHeight = $maxSize;
861874
}
862875

863-
$this->preciseResize((int)round($newWidth), (int)round($newHeight));
864-
return true;
876+
return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
865877
}
866878

867879
/**
@@ -870,6 +882,19 @@ public function resize($maxSize) {
870882
* @return bool
871883
*/
872884
public function preciseResize(int $width, int $height): bool {
885+
$result = $this->preciseResizeNew($width, $height);
886+
imagedestroy($this->resource);
887+
$this->resource = $result;
888+
return is_resource($result);
889+
}
890+
891+
892+
/**
893+
* @param int $width
894+
* @param int $height
895+
* @return resource | bool
896+
*/
897+
public function preciseResizeNew(int $width, int $height) {
873898
if (!$this->valid()) {
874899
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
875900
return false;
@@ -895,9 +920,7 @@ public function preciseResize(int $width, int $height): bool {
895920
imagedestroy($process);
896921
return false;
897922
}
898-
imagedestroy($this->resource);
899-
$this->resource = $process;
900-
return true;
923+
return $process;
901924
}
902925

903926
/**
@@ -968,6 +991,22 @@ public function centerCrop($size = 0) {
968991
* @return bool for success or failure
969992
*/
970993
public function crop(int $x, int $y, int $w, int $h): bool {
994+
$result = $this->cropNew($x, $y, $w, $h);
995+
imagedestroy($this->resource);
996+
$this->resource = $result;
997+
return is_resource($result);
998+
}
999+
1000+
/**
1001+
* Crops the image from point $x$y with dimension $wx$h.
1002+
*
1003+
* @param int $x Horizontal position
1004+
* @param int $y Vertical position
1005+
* @param int $w Width
1006+
* @param int $h Height
1007+
* @return resource | bool
1008+
*/
1009+
public function cropNew(int $x, int $y, int $w, int $h) {
9711010
if (!$this->valid()) {
9721011
$this->logger->error(__METHOD__ . '(): No image loaded', array('app' => 'core'));
9731012
return false;
@@ -992,9 +1031,7 @@ public function crop(int $x, int $y, int $w, int $h): bool {
9921031
imagedestroy($process);
9931032
return false;
9941033
}
995-
imagedestroy($this->resource);
996-
$this->resource = $process;
997-
return true;
1034+
return $process;
9981035
}
9991036

10001037
/**
@@ -1044,6 +1081,55 @@ public function scaleDownToFit($maxWidth, $maxHeight) {
10441081
return false;
10451082
}
10461083

1084+
public function copy(): IImage {
1085+
$image = new OC_Image(null, $this->logger, $this->config);
1086+
$image->resource = imagecreatetruecolor($this->width(), $this->height());
1087+
imagecopy(
1088+
$image->resource(),
1089+
$this->resource(),
1090+
0,
1091+
0,
1092+
0,
1093+
0,
1094+
$this->width(),
1095+
$this->height()
1096+
);
1097+
1098+
return $image;
1099+
}
1100+
1101+
public function cropCopy(int $x, int $y, int $w, int $h): IImage {
1102+
$image = new OC_Image(null, $this->logger, $this->config);
1103+
$image->resource = $this->cropNew($x, $y, $w, $h);
1104+
1105+
return $image;
1106+
}
1107+
1108+
public function preciseResizeCopy(int $width, int $height): IImage {
1109+
$image = new OC_Image(null, $this->logger, $this->config);
1110+
$image->resource = $this->preciseResizeNew($width, $height);
1111+
1112+
return $image;
1113+
}
1114+
1115+
public function resizeCopy(int $maxSize): IImage {
1116+
$image = new OC_Image(null, $this->logger, $this->config);
1117+
$image->resource = $this->resizeNew($maxSize);
1118+
1119+
return $image;
1120+
}
1121+
1122+
1123+
/**
1124+
* Resizes the image preserving ratio, returning a new copy
1125+
*
1126+
* @param integer $maxSize The maximum size of either the width or height.
1127+
* @return bool
1128+
*/
1129+
public function copyResize($maxSize): IImage {
1130+
1131+
}
1132+
10471133
/**
10481134
* Destroys the current image and resets the object
10491135
*/

lib/public/IImage.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,43 @@ public function fitIn($maxWidth, $maxHeight);
190190
* @since 8.1.0
191191
*/
192192
public function scaleDownToFit($maxWidth, $maxHeight);
193+
194+
/**
195+
* create a copy of this image
196+
*
197+
* @return IImage
198+
* @since 19.0.0
199+
*/
200+
public function copy(): IImage;
201+
202+
/**
203+
* create a new cropped copy of this image
204+
*
205+
* @param int $x Horizontal position
206+
* @param int $y Vertical position
207+
* @param int $w Width
208+
* @param int $h Height
209+
* @return IImage
210+
* @since 19.0.0
211+
*/
212+
public function cropCopy(int $x, int $y, int $w, int $h): IImage;
213+
214+
/**
215+
* create a new resized copy of this image
216+
*
217+
* @param int $width
218+
* @param int $height
219+
* @return IImage
220+
* @since 19.0.0
221+
*/
222+
public function preciseResizeCopy(int $width, int $height): IImage;
223+
224+
/**
225+
* create a new resized copy of this image
226+
*
227+
* @param integer $maxSize The maximum size of either the width or height.
228+
* @return IImage
229+
* @since 19.0.0
230+
*/
231+
public function resizeCopy(int $maxSize): IImage;
193232
}

0 commit comments

Comments
 (0)