@@ -137,6 +137,8 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
137137 }
138138
139139 $ previewFolder = $ this ->getPreviewFolder ($ file );
140+ // List every existing preview first instead of trying to find them one by one
141+ $ previewFiles = $ previewFolder ->getDirectoryListing ();
140142
141143 $ previewVersion = '' ;
142144 if ($ file instanceof IVersionedPreviewFile) {
@@ -150,7 +152,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
150152 && preg_match (Imaginary::supportedMimeTypes (), $ mimeType )
151153 && $ this ->config ->getSystemValueString ('preview_imaginary_url ' , 'invalid ' ) !== 'invalid ' ) {
152154 $ crop = $ specifications [0 ]['crop ' ] ?? false ;
153- $ preview = $ this ->getSmallImagePreview ($ previewFolder , $ file , $ mimeType , $ previewVersion , $ crop );
155+ $ preview = $ this ->getSmallImagePreview ($ previewFolder , $ previewFiles , $ file , $ mimeType , $ previewVersion , $ crop );
154156
155157 if ($ preview ->getSize () === 0 ) {
156158 $ preview ->delete ();
@@ -161,7 +163,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
161163 }
162164
163165 // Get the max preview and infer the max preview sizes from that
164- $ maxPreview = $ this ->getMaxPreview ($ previewFolder , $ file , $ mimeType , $ previewVersion );
166+ $ maxPreview = $ this ->getMaxPreview ($ previewFolder , $ previewFiles , $ file , $ mimeType , $ previewVersion );
165167 $ maxPreviewImage = null ; // only load the image when we need it
166168 if ($ maxPreview ->getSize () === 0 ) {
167169 $ maxPreview ->delete ();
@@ -197,7 +199,7 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
197199 // Try to get a cached preview. Else generate (and store) one
198200 try {
199201 try {
200- $ preview = $ this ->getCachedPreview ($ previewFolder , $ width , $ height , $ crop , $ maxPreview ->getMimeType (), $ previewVersion );
202+ $ preview = $ this ->getCachedPreview ($ previewFiles , $ width , $ height , $ crop , $ maxPreview ->getMimeType (), $ previewVersion );
201203 } catch (NotFoundException $ e ) {
202204 if (!$ this ->previewManager ->isMimeSupported ($ mimeType )) {
203205 throw new NotFoundException ();
@@ -208,6 +210,8 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
208210 }
209211
210212 $ preview = $ this ->generatePreview ($ previewFolder , $ maxPreviewImage , $ width , $ height , $ crop , $ maxWidth , $ maxHeight , $ previewVersion );
213+ // New file, augment our array
214+ $ previewFiles [] = $ preview ;
211215 }
212216 } catch (\InvalidArgumentException $ e ) {
213217 throw new NotFoundException ("" , 0 , $ e );
@@ -233,75 +237,19 @@ public function generatePreviews(File $file, array $specifications, $mimeType =
233237 * Generate a small image straight away without generating a max preview first
234238 * Preview generated is 256x256
235239 *
240+ * @param ISimpleFile[] $previewFiles
241+ *
236242 * @throws NotFoundException
237243 */
238- private function getSmallImagePreview (ISimpleFolder $ previewFolder , File $ file , string $ mimeType , string $ prefix , bool $ crop ): ISimpleFile {
239- $ nodes = $ previewFolder ->getDirectoryListing ();
240-
241- foreach ($ nodes as $ node ) {
242- $ name = $ node ->getName ();
243- if (($ prefix === '' || str_starts_with ($ name , $ prefix ))) {
244- // Prefix match
245- if (str_starts_with ($ name , $ prefix . '256-256-crop ' ) && $ crop ) {
246- // Cropped image
247- return $ node ;
248- }
249-
250- if (str_starts_with ($ name , $ prefix . '256-256. ' ) && !$ crop ) {
251- // Uncropped image
252- return $ node ;
253- }
254- }
255- }
256-
257- $ previewProviders = $ this ->previewManager ->getProviders ();
258- foreach ($ previewProviders as $ supportedMimeType => $ providers ) {
259- // Filter out providers that does not support this mime
260- if (!preg_match ($ supportedMimeType , $ mimeType )) {
261- continue ;
262- }
263-
264- foreach ($ providers as $ providerClosure ) {
265- $ provider = $ this ->helper ->getProvider ($ providerClosure );
266- if (!($ provider instanceof IProviderV2)) {
267- continue ;
268- }
269-
270- if (!$ provider ->isAvailable ($ file )) {
271- continue ;
272- }
273-
274- $ preview = $ this ->helper ->getThumbnail ($ provider , $ file , 256 , 256 , $ crop );
275-
276- if (!($ preview instanceof IImage)) {
277- continue ;
278- }
279-
280- // Try to get the extension.
281- try {
282- $ ext = $ this ->getExtention ($ preview ->dataMimeType ());
283- } catch (\InvalidArgumentException $ e ) {
284- // Just continue to the next iteration if this preview doesn't have a valid mimetype
285- continue ;
286- }
287-
288- $ path = $ this ->generatePath (256 , 256 , $ crop , $ preview ->dataMimeType (), $ prefix );
289- try {
290- $ file = $ previewFolder ->newFile ($ path );
291- if ($ preview instanceof IStreamImage) {
292- $ file ->putContent ($ preview ->resource ());
293- } else {
294- $ file ->putContent ($ preview ->data ());
295- }
296- } catch (NotPermittedException $ e ) {
297- throw new NotFoundException ();
298- }
244+ private function getSmallImagePreview (ISimpleFolder $ previewFolder , array $ previewFiles , File $ file , string $ mimeType , string $ prefix , bool $ crop ): ISimpleFile {
245+ $ width = 256 ;
246+ $ height = 256 ;
299247
300- return $ file ;
301- }
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 );
302252 }
303-
304- throw new NotFoundException ('No provider successfully handled the preview generation ' );
305253 }
306254
307255 /**
@@ -398,22 +346,30 @@ public function getNumConcurrentPreviews(string $type): int {
398346
399347 /**
400348 * @param ISimpleFolder $previewFolder
349+ * @param ISimpleFile[] $previewFiles
401350 * @param File $file
402351 * @param string $mimeType
403352 * @param string $prefix
404353 * @return ISimpleFile
405354 * @throws NotFoundException
406355 */
407- private function getMaxPreview (ISimpleFolder $ previewFolder , File $ file , $ mimeType , $ prefix ) {
408- $ nodes = $ previewFolder -> getDirectoryListing ();
409-
410- foreach ($ nodes as $ node ) {
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 ) {
411360 $ name = $ node ->getName ();
412361 if (($ prefix === '' || strpos ($ name , $ prefix ) === 0 ) && strpos ($ name , 'max ' )) {
413362 return $ node ;
414363 }
415364 }
416365
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 ) {
417373 $ previewProviders = $ this ->previewManager ->getProviders ();
418374 foreach ($ previewProviders as $ supportedMimeType => $ providers ) {
419375 // Filter out providers that does not support this mime
@@ -431,13 +387,10 @@ private function getMaxPreview(ISimpleFolder $previewFolder, File $file, $mimeTy
431387 continue ;
432388 }
433389
434- $ maxWidth = $ this ->config ->getSystemValueInt ('preview_max_x ' , 4096 );
435- $ maxHeight = $ this ->config ->getSystemValueInt ('preview_max_y ' , 4096 );
436-
437390 $ previewConcurrency = $ this ->getNumConcurrentPreviews ('preview_concurrency_new ' );
438391 $ sem = self ::guardWithSemaphore (self ::SEMAPHORE_ID_NEW , $ previewConcurrency );
439392 try {
440- $ preview = $ this ->helper ->getThumbnail ($ provider , $ file , $ maxWidth , $ maxHeight );
393+ $ preview = $ this ->helper ->getThumbnail ($ provider , $ file , $ width , $ height );
441394 } finally {
442395 self ::unguardWithSemaphore ($ sem );
443396 }
@@ -446,15 +399,7 @@ private function getMaxPreview(ISimpleFolder $previewFolder, File $file, $mimeTy
446399 continue ;
447400 }
448401
449- // Try to get the extention.
450- try {
451- $ ext = $ this ->getExtention ($ preview ->dataMimeType ());
452- } catch (\InvalidArgumentException $ e ) {
453- // Just continue to the next iteration if this preview doesn't have a valid mimetype
454- continue ;
455- }
456-
457- $ path = $ prefix . (string )$ preview ->width () . '- ' . (string )$ preview ->height () . '-max. ' . $ ext ;
402+ $ path = $ this ->generatePath ($ preview ->width (), $ preview ->height (), $ crop , $ max , $ preview ->dataMimeType (), $ prefix );
458403 try {
459404 $ file = $ previewFolder ->newFile ($ path );
460405 if ($ preview instanceof IStreamImage) {
@@ -470,7 +415,7 @@ private function getMaxPreview(ISimpleFolder $previewFolder, File $file, $mimeTy
470415 }
471416 }
472417
473- throw new NotFoundException ();
418+ throw new NotFoundException (' No provider successfully handled the preview generation ' );
474419 }
475420
476421 /**
@@ -487,15 +432,19 @@ private function getPreviewSize(ISimpleFile $file, string $prefix = '') {
487432 * @param int $width
488433 * @param int $height
489434 * @param bool $crop
435+ * @param bool $max
490436 * @param string $mimeType
491437 * @param string $prefix
492438 * @return string
493439 */
494- private function generatePath ($ width , $ height , $ crop , $ mimeType , $ prefix ) {
440+ private function generatePath ($ width , $ height , $ crop , $ max , $ mimeType , $ prefix ) {
495441 $ path = $ prefix . (string )$ width . '- ' . (string )$ height ;
496442 if ($ crop ) {
497443 $ path .= '-crop ' ;
498444 }
445+ if ($ max ) {
446+ $ path .= '-max ' ;
447+ }
499448
500449 $ ext = $ this ->getExtention ($ mimeType );
501450 $ path .= '. ' . $ ext ;
@@ -637,7 +586,8 @@ private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPrevie
637586 self ::unguardWithSemaphore ($ sem );
638587 }
639588
640- $ path = $ this ->generatePath ($ width , $ height , $ crop , $ preview ->dataMimeType (), $ prefix );
589+
590+ $ path = $ this ->generatePath ($ width , $ height , $ crop , false , $ preview ->dataMimeType (), $ prefix );
641591 try {
642592 $ file = $ previewFolder ->newFile ($ path );
643593 $ file ->putContent ($ preview ->data ());
@@ -649,7 +599,7 @@ private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPrevie
649599 }
650600
651601 /**
652- * @param ISimpleFolder $previewFolder
602+ * @param ISimpleFile[] $files Array of FileInfo, as the result of getDirectoryListing()
653603 * @param int $width
654604 * @param int $height
655605 * @param bool $crop
@@ -659,10 +609,14 @@ private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPrevie
659609 *
660610 * @throws NotFoundException
661611 */
662- private function getCachedPreview (ISimpleFolder $ previewFolder , $ width , $ height , $ crop , $ mimeType , $ prefix ) {
663- $ path = $ this ->generatePath ($ width , $ height , $ crop , $ mimeType , $ prefix );
664-
665- return $ previewFolder ->getFile ($ path );
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 ();
666620 }
667621
668622 /**
0 commit comments