Passed
Push — master ( b6c034...979f40 )
by John
40:53 queued 23:59
created
lib/public/HintException.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -34,49 +34,49 @@
 block discarded – undo
34 34
  * @since 23.0.0
35 35
  */
36 36
 class HintException extends \Exception {
37
-	private $hint;
37
+    private $hint;
38 38
 
39
-	/**
40
-	 * HintException constructor.
41
-	 *
42
-	 * @since 23.0.0
43
-	 * @param string $message  The error message. It will be not revealed to the
44
-	 *                         the user (unless the hint is empty) and thus
45
-	 *                         should be not translated.
46
-	 * @param string $hint     A useful message that is presented to the end
47
-	 *                         user. It should be translated, but must not
48
-	 *                         contain sensitive data.
49
-	 * @param int $code
50
-	 * @param \Exception|null $previous
51
-	 */
52
-	public function __construct($message, $hint = '', $code = 0, \Exception $previous = null) {
53
-		$this->hint = $hint;
54
-		parent::__construct($message, $code, $previous);
55
-	}
39
+    /**
40
+     * HintException constructor.
41
+     *
42
+     * @since 23.0.0
43
+     * @param string $message  The error message. It will be not revealed to the
44
+     *                         the user (unless the hint is empty) and thus
45
+     *                         should be not translated.
46
+     * @param string $hint     A useful message that is presented to the end
47
+     *                         user. It should be translated, but must not
48
+     *                         contain sensitive data.
49
+     * @param int $code
50
+     * @param \Exception|null $previous
51
+     */
52
+    public function __construct($message, $hint = '', $code = 0, \Exception $previous = null) {
53
+        $this->hint = $hint;
54
+        parent::__construct($message, $code, $previous);
55
+    }
56 56
 
57
-	/**
58
-	 * Returns a string representation of this Exception that includes the error
59
-	 * code, the message and the hint.
60
-	 *
61
-	 * @since 23.0.0
62
-	 * @return string
63
-	 */
64
-	public function __toString(): string {
65
-		return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n";
66
-	}
57
+    /**
58
+     * Returns a string representation of this Exception that includes the error
59
+     * code, the message and the hint.
60
+     *
61
+     * @since 23.0.0
62
+     * @return string
63
+     */
64
+    public function __toString(): string {
65
+        return __CLASS__ . ": [{$this->code}]: {$this->message} ({$this->hint})\n";
66
+    }
67 67
 
68
-	/**
69
-	 * Returns the hint with the intention to be presented to the end user. If
70
-	 * an empty hint was specified upon instantiation, the message is returned
71
-	 * instead.
72
-	 *
73
-	 * @since 23.0.0
74
-	 * @return string
75
-	 */
76
-	public function getHint(): string {
77
-		if (empty($this->hint)) {
78
-			return $this->message;
79
-		}
80
-		return $this->hint;
81
-	}
68
+    /**
69
+     * Returns the hint with the intention to be presented to the end user. If
70
+     * an empty hint was specified upon instantiation, the message is returned
71
+     * instead.
72
+     *
73
+     * @since 23.0.0
74
+     * @return string
75
+     */
76
+    public function getHint(): string {
77
+        if (empty($this->hint)) {
78
+            return $this->message;
79
+        }
80
+        return $this->hint;
81
+    }
82 82
 }
Please login to merge, or discard this patch.
lib/public/Files.php 1 patch
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -42,73 +42,73 @@
 block discarded – undo
42 42
  * @deprecated 14.0.0
43 43
  */
44 44
 class Files {
45
-	/**
46
-	 * Recursive deletion of folders
47
-	 * @return bool
48
-	 * @since 5.0.0
49
-	 * @deprecated 14.0.0
50
-	 */
51
-	public static function rmdirr($dir) {
52
-		return \OC_Helper::rmdirr($dir);
53
-	}
45
+    /**
46
+     * Recursive deletion of folders
47
+     * @return bool
48
+     * @since 5.0.0
49
+     * @deprecated 14.0.0
50
+     */
51
+    public static function rmdirr($dir) {
52
+        return \OC_Helper::rmdirr($dir);
53
+    }
54 54
 
55
-	/**
56
-	 * Get the mimetype form a local file
57
-	 * @param string $path
58
-	 * @return string
59
-	 * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
60
-	 * @since 5.0.0
61
-	 * @deprecated 14.0.0
62
-	 */
63
-	public static function getMimeType($path) {
64
-		return \OC::$server->getMimeTypeDetector()->detect($path);
65
-	}
55
+    /**
56
+     * Get the mimetype form a local file
57
+     * @param string $path
58
+     * @return string
59
+     * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
60
+     * @since 5.0.0
61
+     * @deprecated 14.0.0
62
+     */
63
+    public static function getMimeType($path) {
64
+        return \OC::$server->getMimeTypeDetector()->detect($path);
65
+    }
66 66
 
67
-	/**
68
-	 * Search for files by mimetype
69
-	 * @param string $mimetype
70
-	 * @return array
71
-	 * @since 6.0.0
72
-	 * @deprecated 14.0.0
73
-	 */
74
-	public static function searchByMime($mimetype) {
75
-		return \OC\Files\Filesystem::searchByMime($mimetype);
76
-	}
67
+    /**
68
+     * Search for files by mimetype
69
+     * @param string $mimetype
70
+     * @return array
71
+     * @since 6.0.0
72
+     * @deprecated 14.0.0
73
+     */
74
+    public static function searchByMime($mimetype) {
75
+        return \OC\Files\Filesystem::searchByMime($mimetype);
76
+    }
77 77
 
78
-	/**
79
-	 * Copy the contents of one stream to another
80
-	 * @param resource $source
81
-	 * @param resource $target
82
-	 * @return int the number of bytes copied
83
-	 * @since 5.0.0
84
-	 * @deprecated 14.0.0
85
-	 */
86
-	public static function streamCopy($source, $target) {
87
-		[$count, ] = \OC_Helper::streamCopy($source, $target);
88
-		return $count;
89
-	}
78
+    /**
79
+     * Copy the contents of one stream to another
80
+     * @param resource $source
81
+     * @param resource $target
82
+     * @return int the number of bytes copied
83
+     * @since 5.0.0
84
+     * @deprecated 14.0.0
85
+     */
86
+    public static function streamCopy($source, $target) {
87
+        [$count, ] = \OC_Helper::streamCopy($source, $target);
88
+        return $count;
89
+    }
90 90
 
91
-	/**
92
-	 * Adds a suffix to the name in case the file exists
93
-	 * @param string $path
94
-	 * @param string $filename
95
-	 * @return string
96
-	 * @since 5.0.0
97
-	 * @deprecated 14.0.0 use getNonExistingName of the OCP\Files\Folder object
98
-	 */
99
-	public static function buildNotExistingFileName($path, $filename) {
100
-		return \OC_Helper::buildNotExistingFileName($path, $filename);
101
-	}
91
+    /**
92
+     * Adds a suffix to the name in case the file exists
93
+     * @param string $path
94
+     * @param string $filename
95
+     * @return string
96
+     * @since 5.0.0
97
+     * @deprecated 14.0.0 use getNonExistingName of the OCP\Files\Folder object
98
+     */
99
+    public static function buildNotExistingFileName($path, $filename) {
100
+        return \OC_Helper::buildNotExistingFileName($path, $filename);
101
+    }
102 102
 
103
-	/**
104
-	 * Gets the Storage for an app - creates the needed folder if they are not
105
-	 * existent
106
-	 * @param string $app
107
-	 * @return \OC\Files\View
108
-	 * @since 5.0.0
109
-	 * @deprecated 14.0.0 use IAppData instead
110
-	 */
111
-	public static function getStorage($app) {
112
-		return \OC_App::getStorage($app);
113
-	}
103
+    /**
104
+     * Gets the Storage for an app - creates the needed folder if they are not
105
+     * existent
106
+     * @param string $app
107
+     * @return \OC\Files\View
108
+     * @since 5.0.0
109
+     * @deprecated 14.0.0 use IAppData instead
110
+     */
111
+    public static function getStorage($app) {
112
+        return \OC_App::getStorage($app);
113
+    }
114 114
 }
Please login to merge, or discard this patch.
lib/public/Collaboration/AutoComplete/IManager.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -28,17 +28,17 @@
 block discarded – undo
28 28
  * @since 13.0.0
29 29
  */
30 30
 interface IManager {
31
-	/**
32
-	 * @param string $className – class name of the ISorter implementation
33
-	 * @since 13.0.0
34
-	 */
35
-	public function registerSorter($className);
31
+    /**
32
+     * @param string $className – class name of the ISorter implementation
33
+     * @since 13.0.0
34
+     */
35
+    public function registerSorter($className);
36 36
 
37
-	/**
38
-	 * @param array $sorters	list of sorter IDs, separated by "|"
39
-	 * @param array $sortArray	array representation of OCP\Collaboration\Collaborators\ISearchResult
40
-	 * @param array $context	context info of the search, keys: itemType, itemId
41
-	 * @since 13.0.0
42
-	 */
43
-	public function runSorters(array $sorters, array &$sortArray, array $context);
37
+    /**
38
+     * @param array $sorters	list of sorter IDs, separated by "|"
39
+     * @param array $sortArray	array representation of OCP\Collaboration\Collaborators\ISearchResult
40
+     * @param array $context	context info of the search, keys: itemType, itemId
41
+     * @since 13.0.0
42
+     */
43
+    public function runSorters(array $sorters, array &$sortArray, array $context);
44 44
 }
Please login to merge, or discard this patch.
lib/private/Preview/Generator.php 2 patches
Indentation   +597 added lines, -597 removed lines patch added patch discarded remove patch
@@ -48,615 +48,615 @@
 block discarded – undo
48 48
 use Symfony\Component\EventDispatcher\GenericEvent;
49 49
 
50 50
 class Generator {
51
-	public const SEMAPHORE_ID_ALL = 0x0a11;
52
-	public const SEMAPHORE_ID_NEW = 0x07ea;
53
-
54
-	/** @var IPreview */
55
-	private $previewManager;
56
-	/** @var IConfig */
57
-	private $config;
58
-	/** @var IAppData */
59
-	private $appData;
60
-	/** @var GeneratorHelper */
61
-	private $helper;
62
-	/** @var EventDispatcherInterface */
63
-	private $legacyEventDispatcher;
64
-	/** @var IEventDispatcher */
65
-	private $eventDispatcher;
66
-
67
-	public function __construct(
68
-		IConfig $config,
69
-		IPreview $previewManager,
70
-		IAppData $appData,
71
-		GeneratorHelper $helper,
72
-		EventDispatcherInterface $legacyEventDispatcher,
73
-		IEventDispatcher $eventDispatcher
74
-	) {
75
-		$this->config = $config;
76
-		$this->previewManager = $previewManager;
77
-		$this->appData = $appData;
78
-		$this->helper = $helper;
79
-		$this->legacyEventDispatcher = $legacyEventDispatcher;
80
-		$this->eventDispatcher = $eventDispatcher;
81
-	}
82
-
83
-	/**
84
-	 * Returns a preview of a file
85
-	 *
86
-	 * The cache is searched first and if nothing usable was found then a preview is
87
-	 * generated by one of the providers
88
-	 *
89
-	 * @param File $file
90
-	 * @param int $width
91
-	 * @param int $height
92
-	 * @param bool $crop
93
-	 * @param string $mode
94
-	 * @param string $mimeType
95
-	 * @return ISimpleFile
96
-	 * @throws NotFoundException
97
-	 * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
98
-	 */
99
-	public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
100
-		$specification = [
101
-			'width' => $width,
102
-			'height' => $height,
103
-			'crop' => $crop,
104
-			'mode' => $mode,
105
-		];
106
-
107
-		$this->legacyEventDispatcher->dispatch(
108
-			IPreview::EVENT,
109
-			new GenericEvent($file, $specification)
110
-		);
111
-		$this->eventDispatcher->dispatchTyped(new BeforePreviewFetchedEvent(
112
-			$file
113
-		));
114
-
115
-		// since we only ask for one preview, and the generate method return the last one it created, it returns the one we want
116
-		return $this->generatePreviews($file, [$specification], $mimeType);
117
-	}
118
-
119
-	/**
120
-	 * Generates previews of a file
121
-	 *
122
-	 * @param File $file
123
-	 * @param non-empty-array $specifications
124
-	 * @param string $mimeType
125
-	 * @return ISimpleFile the last preview that was generated
126
-	 * @throws NotFoundException
127
-	 * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
128
-	 */
129
-	public function generatePreviews(File $file, array $specifications, $mimeType = null) {
130
-		//Make sure that we can read the file
131
-		if (!$file->isReadable()) {
132
-			throw new NotFoundException('Cannot read file');
133
-		}
134
-
135
-		if ($mimeType === null) {
136
-			$mimeType = $file->getMimeType();
137
-		}
138
-
139
-		$previewFolder = $this->getPreviewFolder($file);
140
-		// List every existing preview first instead of trying to find them one by one
141
-		$previewFiles = $previewFolder->getDirectoryListing();
142
-
143
-		$previewVersion = '';
144
-		if ($file instanceof IVersionedPreviewFile) {
145
-			$previewVersion = $file->getPreviewVersion() . '-';
146
-		}
147
-
148
-		// If imaginary is enabled, and we request a small thumbnail,
149
-		// let's not generate the max preview for performance reasons
150
-		if (count($specifications) === 1
151
-			&& ($specifications[0]['width'] <= 256 || $specifications[0]['height'] <= 256)
152
-			&& preg_match(Imaginary::supportedMimeTypes(), $mimeType)
153
-			&& $this->config->getSystemValueString('preview_imaginary_url', 'invalid') !== 'invalid') {
154
-			$crop = $specifications[0]['crop'] ?? false;
155
-			$preview = $this->getSmallImagePreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion, $crop);
156
-
157
-			if ($preview->getSize() === 0) {
158
-				$preview->delete();
159
-				throw new NotFoundException('Cached preview size 0, invalid!');
160
-			}
161
-
162
-			return $preview;
163
-		}
164
-
165
-		// Get the max preview and infer the max preview sizes from that
166
-		$maxPreview = $this->getMaxPreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion);
167
-		$maxPreviewImage = null; // only load the image when we need it
168
-		if ($maxPreview->getSize() === 0) {
169
-			$maxPreview->delete();
170
-			throw new NotFoundException('Max preview size 0, invalid!');
171
-		}
172
-
173
-		[$maxWidth, $maxHeight] = $this->getPreviewSize($maxPreview, $previewVersion);
174
-
175
-		$preview = null;
176
-
177
-		foreach ($specifications as $specification) {
178
-			$width = $specification['width'] ?? -1;
179
-			$height = $specification['height'] ?? -1;
180
-			$crop = $specification['crop'] ?? false;
181
-			$mode = $specification['mode'] ?? IPreview::MODE_FILL;
182
-
183
-			// If both width and height are -1 we just want the max preview
184
-			if ($width === -1 && $height === -1) {
185
-				$width = $maxWidth;
186
-				$height = $maxHeight;
187
-			}
188
-
189
-			// Calculate the preview size
190
-			[$width, $height] = $this->calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight);
191
-
192
-			// No need to generate a preview that is just the max preview
193
-			if ($width === $maxWidth && $height === $maxHeight) {
194
-				// ensure correct return value if this was the last one
195
-				$preview = $maxPreview;
196
-				continue;
197
-			}
198
-
199
-			// Try to get a cached preview. Else generate (and store) one
200
-			try {
201
-				try {
202
-					$preview = $this->getCachedPreview($previewFiles, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
203
-				} catch (NotFoundException $e) {
204
-					if (!$this->previewManager->isMimeSupported($mimeType)) {
205
-						throw new NotFoundException();
206
-					}
207
-
208
-					if ($maxPreviewImage === null) {
209
-						$maxPreviewImage = $this->helper->getImage($maxPreview);
210
-					}
211
-
212
-					$preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
213
-					// New file, augment our array
214
-					$previewFiles[] = $preview;
215
-				}
216
-			} catch (\InvalidArgumentException $e) {
217
-				throw new NotFoundException("", 0, $e);
218
-			}
219
-
220
-			if ($preview->getSize() === 0) {
221
-				$preview->delete();
222
-				throw new NotFoundException('Cached preview size 0, invalid!');
223
-			}
224
-		}
225
-		assert($preview !== null);
226
-
227
-		// Free memory being used by the embedded image resource.  Without this the image is kept in memory indefinitely.
228
-		// Garbage Collection does NOT free this memory.  We have to do it ourselves.
229
-		if ($maxPreviewImage instanceof \OCP\Image) {
230
-			$maxPreviewImage->destroy();
231
-		}
232
-
233
-		return $preview;
234
-	}
235
-
236
-	/**
237
-	 * Generate a small image straight away without generating a max preview first
238
-	 * Preview generated is 256x256
239
-	 *
240
-	 * @param ISimpleFile[] $previewFiles
241
-	 *
242
-	 * @throws NotFoundException
243
-	 */
244
-	private function getSmallImagePreview(ISimpleFolder $previewFolder, array $previewFiles, File $file, string $mimeType, string $prefix, bool $crop): ISimpleFile {
245
-		$width = 256;
246
-		$height = 256;
247
-
248
-		try {
249
-			return $this->getCachedPreview($previewFiles, $width, $height, $crop, $mimeType, $prefix);
250
-		} catch (NotFoundException $e) {
251
-			return $this->generateProviderPreview($previewFolder, $file, $width, $height, $crop, false, $mimeType, $prefix);
252
-		}
253
-	}
254
-
255
-	/**
256
-	 * Acquire a semaphore of the specified id and concurrency, blocking if necessary.
257
-	 * Return an identifier of the semaphore on success, which can be used to release it via
258
-	 * {@see Generator::unguardWithSemaphore()}.
259
-	 *
260
-	 * @param int $semId
261
-	 * @param int $concurrency
262
-	 * @return false|resource the semaphore on success or false on failure
263
-	 */
264
-	public static function guardWithSemaphore(int $semId, int $concurrency) {
265
-		if (!extension_loaded('sysvsem')) {
266
-			return false;
267
-		}
268
-		$sem = sem_get($semId, $concurrency);
269
-		if ($sem === false) {
270
-			return false;
271
-		}
272
-		if (!sem_acquire($sem)) {
273
-			return false;
274
-		}
275
-		return $sem;
276
-	}
277
-
278
-	/**
279
-	 * Releases the semaphore acquired from {@see Generator::guardWithSemaphore()}.
280
-	 *
281
-	 * @param resource|bool $semId the semaphore identifier returned by guardWithSemaphore
282
-	 * @return bool
283
-	 */
284
-	public static function unguardWithSemaphore($semId): bool {
285
-		if (!is_resource($semId) || !extension_loaded('sysvsem')) {
286
-			return false;
287
-		}
288
-		return sem_release($semId);
289
-	}
290
-
291
-	/**
292
-	 * Get the number of concurrent threads supported by the host.
293
-	 *
294
-	 * @return int number of concurrent threads, or 0 if it cannot be determined
295
-	 */
296
-	public static function getHardwareConcurrency(): int {
297
-		static $width;
298
-		if (!isset($width)) {
299
-			if (is_file("/proc/cpuinfo")) {
300
-				$width = substr_count(file_get_contents("/proc/cpuinfo"), "processor");
301
-			} else {
302
-				$width = 0;
303
-			}
304
-		}
305
-		return $width;
306
-	}
307
-
308
-	/**
309
-	 * Get number of concurrent preview generations from system config
310
-	 *
311
-	 * Two config entries, `preview_concurrency_new` and `preview_concurrency_all`,
312
-	 * are available. If not set, the default values are determined with the hardware concurrency
313
-	 * of the host. In case the hardware concurrency cannot be determined, or the user sets an
314
-	 * invalid value, fallback values are:
315
-	 * For new images whose previews do not exist and need to be generated, 4;
316
-	 * For all preview generation requests, 8.
317
-	 * Value of `preview_concurrency_all` should be greater than or equal to that of
318
-	 * `preview_concurrency_new`, otherwise, the latter is returned.
319
-	 *
320
-	 * @param string $type either `preview_concurrency_new` or `preview_concurrency_all`
321
-	 * @return int number of concurrent preview generations, or -1 if $type is invalid
322
-	 */
323
-	public function getNumConcurrentPreviews(string $type): int {
324
-		static $cached = array();
325
-		if (array_key_exists($type, $cached)) {
326
-			return $cached[$type];
327
-		}
328
-
329
-		$hardwareConcurrency = self::getHardwareConcurrency();
330
-		switch ($type) {
331
-			case "preview_concurrency_all":
332
-				$fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency * 2 : 8;
333
-				$concurrency_all = $this->config->getSystemValueInt($type, $fallback);
334
-				$concurrency_new = $this->getNumConcurrentPreviews("preview_concurrency_new");
335
-				$cached[$type] = max($concurrency_all, $concurrency_new);
336
-				break;
337
-			case "preview_concurrency_new":
338
-				$fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency : 4;
339
-				$cached[$type] = $this->config->getSystemValueInt($type, $fallback);
340
-				break;
341
-			default:
342
-				return -1;
343
-		}
344
-		return $cached[$type];
345
-	}
346
-
347
-	/**
348
-	 * @param ISimpleFolder $previewFolder
349
-	 * @param ISimpleFile[] $previewFiles
350
-	 * @param File $file
351
-	 * @param string $mimeType
352
-	 * @param string $prefix
353
-	 * @return ISimpleFile
354
-	 * @throws NotFoundException
355
-	 */
356
-	private function getMaxPreview(ISimpleFolder $previewFolder, array $previewFiles, File $file, $mimeType, $prefix) {
357
-		// We don't know the max preview size, so we can't use getCachedPreview.
358
-		// It might have been generated with a higher resolution than the current value.
359
-		foreach ($previewFiles as $node) {
360
-			$name = $node->getName();
361
-			if (($prefix === '' || strpos($name, $prefix) === 0) && strpos($name, 'max')) {
362
-				return $node;
363
-			}
364
-		}
365
-
366
-		$maxWidth = $this->config->getSystemValueInt('preview_max_x', 4096);
367
-		$maxHeight = $this->config->getSystemValueInt('preview_max_y', 4096);
368
-
369
-		return $this->generateProviderPreview($previewFolder, $file, $maxWidth, $maxHeight, false, true, $mimeType, $prefix);
370
-	}
371
-
372
-	private function generateProviderPreview(ISimpleFolder $previewFolder, File $file, int $width, int $height, bool $crop, bool $max, string $mimeType, string $prefix) {
373
-		$previewProviders = $this->previewManager->getProviders();
374
-		foreach ($previewProviders as $supportedMimeType => $providers) {
375
-			// Filter out providers that does not support this mime
376
-			if (!preg_match($supportedMimeType, $mimeType)) {
377
-				continue;
378
-			}
379
-
380
-			foreach ($providers as $providerClosure) {
381
-				$provider = $this->helper->getProvider($providerClosure);
382
-				if (!($provider instanceof IProviderV2)) {
383
-					continue;
384
-				}
385
-
386
-				if (!$provider->isAvailable($file)) {
387
-					continue;
388
-				}
389
-
390
-				$previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new');
391
-				$sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency);
392
-				try {
393
-					$preview = $this->helper->getThumbnail($provider, $file, $width, $height);
394
-				} finally {
395
-					self::unguardWithSemaphore($sem);
396
-				}
397
-
398
-				if (!($preview instanceof IImage)) {
399
-					continue;
400
-				}
401
-
402
-				$path = $this->generatePath($preview->width(), $preview->height(), $crop, $max, $preview->dataMimeType(), $prefix);
403
-				try {
404
-					$file = $previewFolder->newFile($path);
405
-					if ($preview instanceof IStreamImage) {
406
-						$file->putContent($preview->resource());
407
-					} else {
408
-						$file->putContent($preview->data());
409
-					}
410
-				} catch (NotPermittedException $e) {
411
-					throw new NotFoundException();
412
-				}
413
-
414
-				return $file;
415
-			}
416
-		}
417
-
418
-		throw new NotFoundException('No provider successfully handled the preview generation');
419
-	}
420
-
421
-	/**
422
-	 * @param ISimpleFile $file
423
-	 * @param string $prefix
424
-	 * @return int[]
425
-	 */
426
-	private function getPreviewSize(ISimpleFile $file, string $prefix = '') {
427
-		$size = explode('-', substr($file->getName(), strlen($prefix)));
428
-		return [(int)$size[0], (int)$size[1]];
429
-	}
430
-
431
-	/**
432
-	 * @param int $width
433
-	 * @param int $height
434
-	 * @param bool $crop
435
-	 * @param bool $max
436
-	 * @param string $mimeType
437
-	 * @param string $prefix
438
-	 * @return string
439
-	 */
440
-	private function generatePath($width, $height, $crop, $max, $mimeType, $prefix) {
441
-		$path = $prefix . (string)$width . '-' . (string)$height;
442
-		if ($crop) {
443
-			$path .= '-crop';
444
-		}
445
-		if ($max) {
446
-			$path .= '-max';
447
-		}
448
-
449
-		$ext = $this->getExtension($mimeType);
450
-		$path .= '.' . $ext;
451
-		return $path;
452
-	}
453
-
454
-
455
-	/**
456
-	 * @param int $width
457
-	 * @param int $height
458
-	 * @param bool $crop
459
-	 * @param string $mode
460
-	 * @param int $maxWidth
461
-	 * @param int $maxHeight
462
-	 * @return int[]
463
-	 */
464
-	private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight) {
465
-		/*
51
+    public const SEMAPHORE_ID_ALL = 0x0a11;
52
+    public const SEMAPHORE_ID_NEW = 0x07ea;
53
+
54
+    /** @var IPreview */
55
+    private $previewManager;
56
+    /** @var IConfig */
57
+    private $config;
58
+    /** @var IAppData */
59
+    private $appData;
60
+    /** @var GeneratorHelper */
61
+    private $helper;
62
+    /** @var EventDispatcherInterface */
63
+    private $legacyEventDispatcher;
64
+    /** @var IEventDispatcher */
65
+    private $eventDispatcher;
66
+
67
+    public function __construct(
68
+        IConfig $config,
69
+        IPreview $previewManager,
70
+        IAppData $appData,
71
+        GeneratorHelper $helper,
72
+        EventDispatcherInterface $legacyEventDispatcher,
73
+        IEventDispatcher $eventDispatcher
74
+    ) {
75
+        $this->config = $config;
76
+        $this->previewManager = $previewManager;
77
+        $this->appData = $appData;
78
+        $this->helper = $helper;
79
+        $this->legacyEventDispatcher = $legacyEventDispatcher;
80
+        $this->eventDispatcher = $eventDispatcher;
81
+    }
82
+
83
+    /**
84
+     * Returns a preview of a file
85
+     *
86
+     * The cache is searched first and if nothing usable was found then a preview is
87
+     * generated by one of the providers
88
+     *
89
+     * @param File $file
90
+     * @param int $width
91
+     * @param int $height
92
+     * @param bool $crop
93
+     * @param string $mode
94
+     * @param string $mimeType
95
+     * @return ISimpleFile
96
+     * @throws NotFoundException
97
+     * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
98
+     */
99
+    public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
100
+        $specification = [
101
+            'width' => $width,
102
+            'height' => $height,
103
+            'crop' => $crop,
104
+            'mode' => $mode,
105
+        ];
106
+
107
+        $this->legacyEventDispatcher->dispatch(
108
+            IPreview::EVENT,
109
+            new GenericEvent($file, $specification)
110
+        );
111
+        $this->eventDispatcher->dispatchTyped(new BeforePreviewFetchedEvent(
112
+            $file
113
+        ));
114
+
115
+        // since we only ask for one preview, and the generate method return the last one it created, it returns the one we want
116
+        return $this->generatePreviews($file, [$specification], $mimeType);
117
+    }
118
+
119
+    /**
120
+     * Generates previews of a file
121
+     *
122
+     * @param File $file
123
+     * @param non-empty-array $specifications
124
+     * @param string $mimeType
125
+     * @return ISimpleFile the last preview that was generated
126
+     * @throws NotFoundException
127
+     * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
128
+     */
129
+    public function generatePreviews(File $file, array $specifications, $mimeType = null) {
130
+        //Make sure that we can read the file
131
+        if (!$file->isReadable()) {
132
+            throw new NotFoundException('Cannot read file');
133
+        }
134
+
135
+        if ($mimeType === null) {
136
+            $mimeType = $file->getMimeType();
137
+        }
138
+
139
+        $previewFolder = $this->getPreviewFolder($file);
140
+        // List every existing preview first instead of trying to find them one by one
141
+        $previewFiles = $previewFolder->getDirectoryListing();
142
+
143
+        $previewVersion = '';
144
+        if ($file instanceof IVersionedPreviewFile) {
145
+            $previewVersion = $file->getPreviewVersion() . '-';
146
+        }
147
+
148
+        // If imaginary is enabled, and we request a small thumbnail,
149
+        // let's not generate the max preview for performance reasons
150
+        if (count($specifications) === 1
151
+            && ($specifications[0]['width'] <= 256 || $specifications[0]['height'] <= 256)
152
+            && preg_match(Imaginary::supportedMimeTypes(), $mimeType)
153
+            && $this->config->getSystemValueString('preview_imaginary_url', 'invalid') !== 'invalid') {
154
+            $crop = $specifications[0]['crop'] ?? false;
155
+            $preview = $this->getSmallImagePreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion, $crop);
156
+
157
+            if ($preview->getSize() === 0) {
158
+                $preview->delete();
159
+                throw new NotFoundException('Cached preview size 0, invalid!');
160
+            }
161
+
162
+            return $preview;
163
+        }
164
+
165
+        // Get the max preview and infer the max preview sizes from that
166
+        $maxPreview = $this->getMaxPreview($previewFolder, $previewFiles, $file, $mimeType, $previewVersion);
167
+        $maxPreviewImage = null; // only load the image when we need it
168
+        if ($maxPreview->getSize() === 0) {
169
+            $maxPreview->delete();
170
+            throw new NotFoundException('Max preview size 0, invalid!');
171
+        }
172
+
173
+        [$maxWidth, $maxHeight] = $this->getPreviewSize($maxPreview, $previewVersion);
174
+
175
+        $preview = null;
176
+
177
+        foreach ($specifications as $specification) {
178
+            $width = $specification['width'] ?? -1;
179
+            $height = $specification['height'] ?? -1;
180
+            $crop = $specification['crop'] ?? false;
181
+            $mode = $specification['mode'] ?? IPreview::MODE_FILL;
182
+
183
+            // If both width and height are -1 we just want the max preview
184
+            if ($width === -1 && $height === -1) {
185
+                $width = $maxWidth;
186
+                $height = $maxHeight;
187
+            }
188
+
189
+            // Calculate the preview size
190
+            [$width, $height] = $this->calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight);
191
+
192
+            // No need to generate a preview that is just the max preview
193
+            if ($width === $maxWidth && $height === $maxHeight) {
194
+                // ensure correct return value if this was the last one
195
+                $preview = $maxPreview;
196
+                continue;
197
+            }
198
+
199
+            // Try to get a cached preview. Else generate (and store) one
200
+            try {
201
+                try {
202
+                    $preview = $this->getCachedPreview($previewFiles, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
203
+                } catch (NotFoundException $e) {
204
+                    if (!$this->previewManager->isMimeSupported($mimeType)) {
205
+                        throw new NotFoundException();
206
+                    }
207
+
208
+                    if ($maxPreviewImage === null) {
209
+                        $maxPreviewImage = $this->helper->getImage($maxPreview);
210
+                    }
211
+
212
+                    $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
213
+                    // New file, augment our array
214
+                    $previewFiles[] = $preview;
215
+                }
216
+            } catch (\InvalidArgumentException $e) {
217
+                throw new NotFoundException("", 0, $e);
218
+            }
219
+
220
+            if ($preview->getSize() === 0) {
221
+                $preview->delete();
222
+                throw new NotFoundException('Cached preview size 0, invalid!');
223
+            }
224
+        }
225
+        assert($preview !== null);
226
+
227
+        // Free memory being used by the embedded image resource.  Without this the image is kept in memory indefinitely.
228
+        // Garbage Collection does NOT free this memory.  We have to do it ourselves.
229
+        if ($maxPreviewImage instanceof \OCP\Image) {
230
+            $maxPreviewImage->destroy();
231
+        }
232
+
233
+        return $preview;
234
+    }
235
+
236
+    /**
237
+     * Generate a small image straight away without generating a max preview first
238
+     * Preview generated is 256x256
239
+     *
240
+     * @param ISimpleFile[] $previewFiles
241
+     *
242
+     * @throws NotFoundException
243
+     */
244
+    private function getSmallImagePreview(ISimpleFolder $previewFolder, array $previewFiles, File $file, string $mimeType, string $prefix, bool $crop): ISimpleFile {
245
+        $width = 256;
246
+        $height = 256;
247
+
248
+        try {
249
+            return $this->getCachedPreview($previewFiles, $width, $height, $crop, $mimeType, $prefix);
250
+        } catch (NotFoundException $e) {
251
+            return $this->generateProviderPreview($previewFolder, $file, $width, $height, $crop, false, $mimeType, $prefix);
252
+        }
253
+    }
254
+
255
+    /**
256
+     * Acquire a semaphore of the specified id and concurrency, blocking if necessary.
257
+     * Return an identifier of the semaphore on success, which can be used to release it via
258
+     * {@see Generator::unguardWithSemaphore()}.
259
+     *
260
+     * @param int $semId
261
+     * @param int $concurrency
262
+     * @return false|resource the semaphore on success or false on failure
263
+     */
264
+    public static function guardWithSemaphore(int $semId, int $concurrency) {
265
+        if (!extension_loaded('sysvsem')) {
266
+            return false;
267
+        }
268
+        $sem = sem_get($semId, $concurrency);
269
+        if ($sem === false) {
270
+            return false;
271
+        }
272
+        if (!sem_acquire($sem)) {
273
+            return false;
274
+        }
275
+        return $sem;
276
+    }
277
+
278
+    /**
279
+     * Releases the semaphore acquired from {@see Generator::guardWithSemaphore()}.
280
+     *
281
+     * @param resource|bool $semId the semaphore identifier returned by guardWithSemaphore
282
+     * @return bool
283
+     */
284
+    public static function unguardWithSemaphore($semId): bool {
285
+        if (!is_resource($semId) || !extension_loaded('sysvsem')) {
286
+            return false;
287
+        }
288
+        return sem_release($semId);
289
+    }
290
+
291
+    /**
292
+     * Get the number of concurrent threads supported by the host.
293
+     *
294
+     * @return int number of concurrent threads, or 0 if it cannot be determined
295
+     */
296
+    public static function getHardwareConcurrency(): int {
297
+        static $width;
298
+        if (!isset($width)) {
299
+            if (is_file("/proc/cpuinfo")) {
300
+                $width = substr_count(file_get_contents("/proc/cpuinfo"), "processor");
301
+            } else {
302
+                $width = 0;
303
+            }
304
+        }
305
+        return $width;
306
+    }
307
+
308
+    /**
309
+     * Get number of concurrent preview generations from system config
310
+     *
311
+     * Two config entries, `preview_concurrency_new` and `preview_concurrency_all`,
312
+     * are available. If not set, the default values are determined with the hardware concurrency
313
+     * of the host. In case the hardware concurrency cannot be determined, or the user sets an
314
+     * invalid value, fallback values are:
315
+     * For new images whose previews do not exist and need to be generated, 4;
316
+     * For all preview generation requests, 8.
317
+     * Value of `preview_concurrency_all` should be greater than or equal to that of
318
+     * `preview_concurrency_new`, otherwise, the latter is returned.
319
+     *
320
+     * @param string $type either `preview_concurrency_new` or `preview_concurrency_all`
321
+     * @return int number of concurrent preview generations, or -1 if $type is invalid
322
+     */
323
+    public function getNumConcurrentPreviews(string $type): int {
324
+        static $cached = array();
325
+        if (array_key_exists($type, $cached)) {
326
+            return $cached[$type];
327
+        }
328
+
329
+        $hardwareConcurrency = self::getHardwareConcurrency();
330
+        switch ($type) {
331
+            case "preview_concurrency_all":
332
+                $fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency * 2 : 8;
333
+                $concurrency_all = $this->config->getSystemValueInt($type, $fallback);
334
+                $concurrency_new = $this->getNumConcurrentPreviews("preview_concurrency_new");
335
+                $cached[$type] = max($concurrency_all, $concurrency_new);
336
+                break;
337
+            case "preview_concurrency_new":
338
+                $fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency : 4;
339
+                $cached[$type] = $this->config->getSystemValueInt($type, $fallback);
340
+                break;
341
+            default:
342
+                return -1;
343
+        }
344
+        return $cached[$type];
345
+    }
346
+
347
+    /**
348
+     * @param ISimpleFolder $previewFolder
349
+     * @param ISimpleFile[] $previewFiles
350
+     * @param File $file
351
+     * @param string $mimeType
352
+     * @param string $prefix
353
+     * @return ISimpleFile
354
+     * @throws NotFoundException
355
+     */
356
+    private function getMaxPreview(ISimpleFolder $previewFolder, array $previewFiles, File $file, $mimeType, $prefix) {
357
+        // We don't know the max preview size, so we can't use getCachedPreview.
358
+        // It might have been generated with a higher resolution than the current value.
359
+        foreach ($previewFiles as $node) {
360
+            $name = $node->getName();
361
+            if (($prefix === '' || strpos($name, $prefix) === 0) && strpos($name, 'max')) {
362
+                return $node;
363
+            }
364
+        }
365
+
366
+        $maxWidth = $this->config->getSystemValueInt('preview_max_x', 4096);
367
+        $maxHeight = $this->config->getSystemValueInt('preview_max_y', 4096);
368
+
369
+        return $this->generateProviderPreview($previewFolder, $file, $maxWidth, $maxHeight, false, true, $mimeType, $prefix);
370
+    }
371
+
372
+    private function generateProviderPreview(ISimpleFolder $previewFolder, File $file, int $width, int $height, bool $crop, bool $max, string $mimeType, string $prefix) {
373
+        $previewProviders = $this->previewManager->getProviders();
374
+        foreach ($previewProviders as $supportedMimeType => $providers) {
375
+            // Filter out providers that does not support this mime
376
+            if (!preg_match($supportedMimeType, $mimeType)) {
377
+                continue;
378
+            }
379
+
380
+            foreach ($providers as $providerClosure) {
381
+                $provider = $this->helper->getProvider($providerClosure);
382
+                if (!($provider instanceof IProviderV2)) {
383
+                    continue;
384
+                }
385
+
386
+                if (!$provider->isAvailable($file)) {
387
+                    continue;
388
+                }
389
+
390
+                $previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new');
391
+                $sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency);
392
+                try {
393
+                    $preview = $this->helper->getThumbnail($provider, $file, $width, $height);
394
+                } finally {
395
+                    self::unguardWithSemaphore($sem);
396
+                }
397
+
398
+                if (!($preview instanceof IImage)) {
399
+                    continue;
400
+                }
401
+
402
+                $path = $this->generatePath($preview->width(), $preview->height(), $crop, $max, $preview->dataMimeType(), $prefix);
403
+                try {
404
+                    $file = $previewFolder->newFile($path);
405
+                    if ($preview instanceof IStreamImage) {
406
+                        $file->putContent($preview->resource());
407
+                    } else {
408
+                        $file->putContent($preview->data());
409
+                    }
410
+                } catch (NotPermittedException $e) {
411
+                    throw new NotFoundException();
412
+                }
413
+
414
+                return $file;
415
+            }
416
+        }
417
+
418
+        throw new NotFoundException('No provider successfully handled the preview generation');
419
+    }
420
+
421
+    /**
422
+     * @param ISimpleFile $file
423
+     * @param string $prefix
424
+     * @return int[]
425
+     */
426
+    private function getPreviewSize(ISimpleFile $file, string $prefix = '') {
427
+        $size = explode('-', substr($file->getName(), strlen($prefix)));
428
+        return [(int)$size[0], (int)$size[1]];
429
+    }
430
+
431
+    /**
432
+     * @param int $width
433
+     * @param int $height
434
+     * @param bool $crop
435
+     * @param bool $max
436
+     * @param string $mimeType
437
+     * @param string $prefix
438
+     * @return string
439
+     */
440
+    private function generatePath($width, $height, $crop, $max, $mimeType, $prefix) {
441
+        $path = $prefix . (string)$width . '-' . (string)$height;
442
+        if ($crop) {
443
+            $path .= '-crop';
444
+        }
445
+        if ($max) {
446
+            $path .= '-max';
447
+        }
448
+
449
+        $ext = $this->getExtension($mimeType);
450
+        $path .= '.' . $ext;
451
+        return $path;
452
+    }
453
+
454
+
455
+    /**
456
+     * @param int $width
457
+     * @param int $height
458
+     * @param bool $crop
459
+     * @param string $mode
460
+     * @param int $maxWidth
461
+     * @param int $maxHeight
462
+     * @return int[]
463
+     */
464
+    private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight) {
465
+        /*
466 466
 		 * If we are not cropping we have to make sure the requested image
467 467
 		 * respects the aspect ratio of the original.
468 468
 		 */
469
-		if (!$crop) {
470
-			$ratio = $maxHeight / $maxWidth;
469
+        if (!$crop) {
470
+            $ratio = $maxHeight / $maxWidth;
471 471
 
472
-			if ($width === -1) {
473
-				$width = $height / $ratio;
474
-			}
475
-			if ($height === -1) {
476
-				$height = $width * $ratio;
477
-			}
472
+            if ($width === -1) {
473
+                $width = $height / $ratio;
474
+            }
475
+            if ($height === -1) {
476
+                $height = $width * $ratio;
477
+            }
478 478
 
479
-			$ratioH = $height / $maxHeight;
480
-			$ratioW = $width / $maxWidth;
479
+            $ratioH = $height / $maxHeight;
480
+            $ratioW = $width / $maxWidth;
481 481
 
482
-			/*
482
+            /*
483 483
 			 * Fill means that the $height and $width are the max
484 484
 			 * Cover means min.
485 485
 			 */
486
-			if ($mode === IPreview::MODE_FILL) {
487
-				if ($ratioH > $ratioW) {
488
-					$height = $width * $ratio;
489
-				} else {
490
-					$width = $height / $ratio;
491
-				}
492
-			} elseif ($mode === IPreview::MODE_COVER) {
493
-				if ($ratioH > $ratioW) {
494
-					$width = $height / $ratio;
495
-				} else {
496
-					$height = $width * $ratio;
497
-				}
498
-			}
499
-		}
500
-
501
-		if ($height !== $maxHeight && $width !== $maxWidth) {
502
-			/*
486
+            if ($mode === IPreview::MODE_FILL) {
487
+                if ($ratioH > $ratioW) {
488
+                    $height = $width * $ratio;
489
+                } else {
490
+                    $width = $height / $ratio;
491
+                }
492
+            } elseif ($mode === IPreview::MODE_COVER) {
493
+                if ($ratioH > $ratioW) {
494
+                    $width = $height / $ratio;
495
+                } else {
496
+                    $height = $width * $ratio;
497
+                }
498
+            }
499
+        }
500
+
501
+        if ($height !== $maxHeight && $width !== $maxWidth) {
502
+            /*
503 503
 			 * Scale to the nearest power of four
504 504
 			 */
505
-			$pow4height = 4 ** ceil(log($height) / log(4));
506
-			$pow4width = 4 ** ceil(log($width) / log(4));
507
-
508
-			// Minimum size is 64
509
-			$pow4height = max($pow4height, 64);
510
-			$pow4width = max($pow4width, 64);
511
-
512
-			$ratioH = $height / $pow4height;
513
-			$ratioW = $width / $pow4width;
514
-
515
-			if ($ratioH < $ratioW) {
516
-				$width = $pow4width;
517
-				$height /= $ratioW;
518
-			} else {
519
-				$height = $pow4height;
520
-				$width /= $ratioH;
521
-			}
522
-		}
523
-
524
-		/*
505
+            $pow4height = 4 ** ceil(log($height) / log(4));
506
+            $pow4width = 4 ** ceil(log($width) / log(4));
507
+
508
+            // Minimum size is 64
509
+            $pow4height = max($pow4height, 64);
510
+            $pow4width = max($pow4width, 64);
511
+
512
+            $ratioH = $height / $pow4height;
513
+            $ratioW = $width / $pow4width;
514
+
515
+            if ($ratioH < $ratioW) {
516
+                $width = $pow4width;
517
+                $height /= $ratioW;
518
+            } else {
519
+                $height = $pow4height;
520
+                $width /= $ratioH;
521
+            }
522
+        }
523
+
524
+        /*
525 525
 		 * Make sure the requested height and width fall within the max
526 526
 		 * of the preview.
527 527
 		 */
528
-		if ($height > $maxHeight) {
529
-			$ratio = $height / $maxHeight;
530
-			$height = $maxHeight;
531
-			$width /= $ratio;
532
-		}
533
-		if ($width > $maxWidth) {
534
-			$ratio = $width / $maxWidth;
535
-			$width = $maxWidth;
536
-			$height /= $ratio;
537
-		}
538
-
539
-		return [(int)round($width), (int)round($height)];
540
-	}
541
-
542
-	/**
543
-	 * @param ISimpleFolder $previewFolder
544
-	 * @param ISimpleFile $maxPreview
545
-	 * @param int $width
546
-	 * @param int $height
547
-	 * @param bool $crop
548
-	 * @param int $maxWidth
549
-	 * @param int $maxHeight
550
-	 * @param string $prefix
551
-	 * @return ISimpleFile
552
-	 * @throws NotFoundException
553
-	 * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
554
-	 */
555
-	private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
556
-		$preview = $maxPreview;
557
-		if (!$preview->valid()) {
558
-			throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
559
-		}
560
-
561
-		$previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new');
562
-		$sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency);
563
-		try {
564
-			if ($crop) {
565
-				if ($height !== $preview->height() && $width !== $preview->width()) {
566
-					//Resize
567
-					$widthR = $preview->width() / $width;
568
-					$heightR = $preview->height() / $height;
569
-
570
-					if ($widthR > $heightR) {
571
-						$scaleH = $height;
572
-						$scaleW = $maxWidth / $heightR;
573
-					} else {
574
-						$scaleH = $maxHeight / $widthR;
575
-						$scaleW = $width;
576
-					}
577
-					$preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
578
-				}
579
-				$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
580
-				$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
581
-				$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
582
-			} else {
583
-				$preview = $maxPreview->resizeCopy(max($width, $height));
584
-			}
585
-		} finally {
586
-			self::unguardWithSemaphore($sem);
587
-		}
588
-
589
-
590
-		$path = $this->generatePath($width, $height, $crop, false, $preview->dataMimeType(), $prefix);
591
-		try {
592
-			$file = $previewFolder->newFile($path);
593
-			$file->putContent($preview->data());
594
-		} catch (NotPermittedException $e) {
595
-			throw new NotFoundException();
596
-		}
597
-
598
-		return $file;
599
-	}
600
-
601
-	/**
602
-	 * @param ISimpleFile[] $files Array of FileInfo, as the result of getDirectoryListing()
603
-	 * @param int $width
604
-	 * @param int $height
605
-	 * @param bool $crop
606
-	 * @param string $mimeType
607
-	 * @param string $prefix
608
-	 * @return ISimpleFile
609
-	 *
610
-	 * @throws NotFoundException
611
-	 */
612
-	private function getCachedPreview($files, $width, $height, $crop, $mimeType, $prefix) {
613
-		$path = $this->generatePath($width, $height, $crop, false, $mimeType, $prefix);
614
-		foreach ($files as $file) {
615
-			if ($file->getName() === $path) {
616
-				return $file;
617
-			}
618
-		}
619
-		throw new NotFoundException();
620
-	}
621
-
622
-	/**
623
-	 * Get the specific preview folder for this file
624
-	 *
625
-	 * @param File $file
626
-	 * @return ISimpleFolder
627
-	 *
628
-	 * @throws InvalidPathException
629
-	 * @throws NotFoundException
630
-	 * @throws NotPermittedException
631
-	 */
632
-	private function getPreviewFolder(File $file) {
633
-		// Obtain file id outside of try catch block to prevent the creation of an existing folder
634
-		$fileId = (string)$file->getId();
635
-
636
-		try {
637
-			$folder = $this->appData->getFolder($fileId);
638
-		} catch (NotFoundException $e) {
639
-			$folder = $this->appData->newFolder($fileId);
640
-		}
641
-
642
-		return $folder;
643
-	}
644
-
645
-	/**
646
-	 * @param string $mimeType
647
-	 * @return null|string
648
-	 * @throws \InvalidArgumentException
649
-	 */
650
-	private function getExtension($mimeType) {
651
-		switch ($mimeType) {
652
-			case 'image/png':
653
-				return 'png';
654
-			case 'image/jpeg':
655
-				return 'jpg';
656
-			case 'image/gif':
657
-				return 'gif';
658
-			default:
659
-				throw new \InvalidArgumentException('Not a valid mimetype: "' . $mimeType . '"');
660
-		}
661
-	}
528
+        if ($height > $maxHeight) {
529
+            $ratio = $height / $maxHeight;
530
+            $height = $maxHeight;
531
+            $width /= $ratio;
532
+        }
533
+        if ($width > $maxWidth) {
534
+            $ratio = $width / $maxWidth;
535
+            $width = $maxWidth;
536
+            $height /= $ratio;
537
+        }
538
+
539
+        return [(int)round($width), (int)round($height)];
540
+    }
541
+
542
+    /**
543
+     * @param ISimpleFolder $previewFolder
544
+     * @param ISimpleFile $maxPreview
545
+     * @param int $width
546
+     * @param int $height
547
+     * @param bool $crop
548
+     * @param int $maxWidth
549
+     * @param int $maxHeight
550
+     * @param string $prefix
551
+     * @return ISimpleFile
552
+     * @throws NotFoundException
553
+     * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
554
+     */
555
+    private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
556
+        $preview = $maxPreview;
557
+        if (!$preview->valid()) {
558
+            throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
559
+        }
560
+
561
+        $previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new');
562
+        $sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency);
563
+        try {
564
+            if ($crop) {
565
+                if ($height !== $preview->height() && $width !== $preview->width()) {
566
+                    //Resize
567
+                    $widthR = $preview->width() / $width;
568
+                    $heightR = $preview->height() / $height;
569
+
570
+                    if ($widthR > $heightR) {
571
+                        $scaleH = $height;
572
+                        $scaleW = $maxWidth / $heightR;
573
+                    } else {
574
+                        $scaleH = $maxHeight / $widthR;
575
+                        $scaleW = $width;
576
+                    }
577
+                    $preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
578
+                }
579
+                $cropX = (int)floor(abs($width - $preview->width()) * 0.5);
580
+                $cropY = (int)floor(abs($height - $preview->height()) * 0.5);
581
+                $preview = $preview->cropCopy($cropX, $cropY, $width, $height);
582
+            } else {
583
+                $preview = $maxPreview->resizeCopy(max($width, $height));
584
+            }
585
+        } finally {
586
+            self::unguardWithSemaphore($sem);
587
+        }
588
+
589
+
590
+        $path = $this->generatePath($width, $height, $crop, false, $preview->dataMimeType(), $prefix);
591
+        try {
592
+            $file = $previewFolder->newFile($path);
593
+            $file->putContent($preview->data());
594
+        } catch (NotPermittedException $e) {
595
+            throw new NotFoundException();
596
+        }
597
+
598
+        return $file;
599
+    }
600
+
601
+    /**
602
+     * @param ISimpleFile[] $files Array of FileInfo, as the result of getDirectoryListing()
603
+     * @param int $width
604
+     * @param int $height
605
+     * @param bool $crop
606
+     * @param string $mimeType
607
+     * @param string $prefix
608
+     * @return ISimpleFile
609
+     *
610
+     * @throws NotFoundException
611
+     */
612
+    private function getCachedPreview($files, $width, $height, $crop, $mimeType, $prefix) {
613
+        $path = $this->generatePath($width, $height, $crop, false, $mimeType, $prefix);
614
+        foreach ($files as $file) {
615
+            if ($file->getName() === $path) {
616
+                return $file;
617
+            }
618
+        }
619
+        throw new NotFoundException();
620
+    }
621
+
622
+    /**
623
+     * Get the specific preview folder for this file
624
+     *
625
+     * @param File $file
626
+     * @return ISimpleFolder
627
+     *
628
+     * @throws InvalidPathException
629
+     * @throws NotFoundException
630
+     * @throws NotPermittedException
631
+     */
632
+    private function getPreviewFolder(File $file) {
633
+        // Obtain file id outside of try catch block to prevent the creation of an existing folder
634
+        $fileId = (string)$file->getId();
635
+
636
+        try {
637
+            $folder = $this->appData->getFolder($fileId);
638
+        } catch (NotFoundException $e) {
639
+            $folder = $this->appData->newFolder($fileId);
640
+        }
641
+
642
+        return $folder;
643
+    }
644
+
645
+    /**
646
+     * @param string $mimeType
647
+     * @return null|string
648
+     * @throws \InvalidArgumentException
649
+     */
650
+    private function getExtension($mimeType) {
651
+        switch ($mimeType) {
652
+            case 'image/png':
653
+                return 'png';
654
+            case 'image/jpeg':
655
+                return 'jpg';
656
+            case 'image/gif':
657
+                return 'gif';
658
+            default:
659
+                throw new \InvalidArgumentException('Not a valid mimetype: "' . $mimeType . '"');
660
+        }
661
+    }
662 662
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 
143 143
 		$previewVersion = '';
144 144
 		if ($file instanceof IVersionedPreviewFile) {
145
-			$previewVersion = $file->getPreviewVersion() . '-';
145
+			$previewVersion = $file->getPreviewVersion().'-';
146 146
 		}
147 147
 
148 148
 		// If imaginary is enabled, and we request a small thumbnail,
@@ -425,7 +425,7 @@  discard block
 block discarded – undo
425 425
 	 */
426 426
 	private function getPreviewSize(ISimpleFile $file, string $prefix = '') {
427 427
 		$size = explode('-', substr($file->getName(), strlen($prefix)));
428
-		return [(int)$size[0], (int)$size[1]];
428
+		return [(int) $size[0], (int) $size[1]];
429 429
 	}
430 430
 
431 431
 	/**
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
 	 * @return string
439 439
 	 */
440 440
 	private function generatePath($width, $height, $crop, $max, $mimeType, $prefix) {
441
-		$path = $prefix . (string)$width . '-' . (string)$height;
441
+		$path = $prefix.(string) $width.'-'.(string) $height;
442 442
 		if ($crop) {
443 443
 			$path .= '-crop';
444 444
 		}
@@ -447,7 +447,7 @@  discard block
 block discarded – undo
447 447
 		}
448 448
 
449 449
 		$ext = $this->getExtension($mimeType);
450
-		$path .= '.' . $ext;
450
+		$path .= '.'.$ext;
451 451
 		return $path;
452 452
 	}
453 453
 
@@ -536,7 +536,7 @@  discard block
 block discarded – undo
536 536
 			$height /= $ratio;
537 537
 		}
538 538
 
539
-		return [(int)round($width), (int)round($height)];
539
+		return [(int) round($width), (int) round($height)];
540 540
 	}
541 541
 
542 542
 	/**
@@ -574,10 +574,10 @@  discard block
 block discarded – undo
574 574
 						$scaleH = $maxHeight / $widthR;
575 575
 						$scaleW = $width;
576 576
 					}
577
-					$preview = $preview->preciseResizeCopy((int)round($scaleW), (int)round($scaleH));
577
+					$preview = $preview->preciseResizeCopy((int) round($scaleW), (int) round($scaleH));
578 578
 				}
579
-				$cropX = (int)floor(abs($width - $preview->width()) * 0.5);
580
-				$cropY = (int)floor(abs($height - $preview->height()) * 0.5);
579
+				$cropX = (int) floor(abs($width - $preview->width()) * 0.5);
580
+				$cropY = (int) floor(abs($height - $preview->height()) * 0.5);
581 581
 				$preview = $preview->cropCopy($cropX, $cropY, $width, $height);
582 582
 			} else {
583 583
 				$preview = $maxPreview->resizeCopy(max($width, $height));
@@ -631,7 +631,7 @@  discard block
 block discarded – undo
631 631
 	 */
632 632
 	private function getPreviewFolder(File $file) {
633 633
 		// Obtain file id outside of try catch block to prevent the creation of an existing folder
634
-		$fileId = (string)$file->getId();
634
+		$fileId = (string) $file->getId();
635 635
 
636 636
 		try {
637 637
 			$folder = $this->appData->getFolder($fileId);
@@ -656,7 +656,7 @@  discard block
 block discarded – undo
656 656
 			case 'image/gif':
657 657
 				return 'gif';
658 658
 			default:
659
-				throw new \InvalidArgumentException('Not a valid mimetype: "' . $mimeType . '"');
659
+				throw new \InvalidArgumentException('Not a valid mimetype: "'.$mimeType.'"');
660 660
 		}
661 661
 	}
662 662
 }
Please login to merge, or discard this patch.