Skip to content

Commit 7d38687

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 5cd12cd commit 7d38687

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
@@ -138,6 +138,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
138138

139139
// Get the max preview and infer the max preview sizes from that
140140
$maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType, $previewVersion);
141+
$maxPreviewImage = null; // only load the image when we need it
141142
if ($maxPreview->getSize() === 0) {
142143
$maxPreview->delete();
143144
throw new NotFoundException('Max preview size 0, invalid!');
@@ -174,7 +175,11 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
174175
try {
175176
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
176177
} catch (NotFoundException $e) {
177-
$preview = $this->generatePreview($previewFolder, $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
178+
if ($maxPreviewImage === null) {
179+
$maxPreviewImage = $this->helper->getImage($maxPreview);
180+
}
181+
182+
$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
178183
}
179184
} catch (\InvalidArgumentException $e) {
180185
throw new NotFoundException();
@@ -386,9 +391,8 @@ private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHei
386391
* @throws NotFoundException
387392
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
388393
*/
389-
private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
390-
$preview = $this->helper->getImage($maxPreview);
391-
394+
private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
395+
$preview = $maxPreview;
392396
if (!$preview->valid()) {
393397
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
394398
}
@@ -406,13 +410,13 @@ private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxP
406410
$scaleH = $maxHeight / $widthR;
407411
$scaleW = $width;
408412
}
409-
$preview->preciseResize((int)round($scaleW), (int)round($scaleH));
413+
$preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
410414
}
411415
$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
412416
$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
413-
$preview->crop($cropX, $cropY, $width, $height);
417+
$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
414418
} else {
415-
$preview->resize(max($width, $height));
419+
$preview = $maxPreview->resizeCopy(max($width, $height));
416420
}
417421

418422

lib/private/legacy/OC_Image.php

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

42+
use OCP\IImage;
43+
4244
/**
4345
* Class for basic image manipulation
4446
*/
@@ -845,6 +847,17 @@ private function imagecreatefrombmp($fileName) {
845847
* @return bool
846848
*/
847849
public function resize($maxSize) {
850+
$result = $this->resizeNew($maxSize);
851+
imagedestroy($this->resource);
852+
$this->resource = $result;
853+
return is_resource($result);
854+
}
855+
856+
/**
857+
* @param $maxSize
858+
* @return resource | bool
859+
*/
860+
private function resizeNew($maxSize) {
848861
if (!$this->valid()) {
849862
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
850863
return false;
@@ -861,8 +874,7 @@ public function resize($maxSize) {
861874
$newHeight = $maxSize;
862875
}
863876

864-
$this->preciseResize((int)round($newWidth), (int)round($newHeight));
865-
return true;
877+
return $this->preciseResizeNew((int)round($newWidth), (int)round($newHeight));
866878
}
867879

868880
/**
@@ -871,6 +883,19 @@ public function resize($maxSize) {
871883
* @return bool
872884
*/
873885
public function preciseResize(int $width, int $height): bool {
886+
$result = $this->preciseResizeNew($width, $height);
887+
imagedestroy($this->resource);
888+
$this->resource = $result;
889+
return is_resource($result);
890+
}
891+
892+
893+
/**
894+
* @param int $width
895+
* @param int $height
896+
* @return resource | bool
897+
*/
898+
public function preciseResizeNew(int $width, int $height) {
874899
if (!$this->valid()) {
875900
$this->logger->error(__METHOD__ . '(): No image loaded', ['app' => 'core']);
876901
return false;
@@ -896,9 +921,7 @@ public function preciseResize(int $width, int $height): bool {
896921
imagedestroy($process);
897922
return false;
898923
}
899-
imagedestroy($this->resource);
900-
$this->resource = $process;
901-
return true;
924+
return $process;
902925
}
903926

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

10011038
/**
@@ -1045,6 +1082,55 @@ public function scaleDownToFit($maxWidth, $maxHeight) {
10451082
return false;
10461083
}
10471084

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

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)