string, // Always usable URL (thumbnail or placeholder) * 'isFinal' => bool, // true if thumbnail ready, false if placeholder * 'thumbUrl' => string // Real thumbnail URL (for lazy loading) * ] */ public static function getThumbnail( string $rootPath, string $localPath, string $pageId, int $width, int $height, int $quality = 80, ?string $placeholderId = null ): array { $fullPath = $rootPath . $localPath; $thumbUrl = self::buildThumbnailUrl($rootPath, $localPath, $pageId, $width, $height, $quality); // Check if cached $cachePath = self::getCachePath($fullPath, $width, $height, $quality); $isCached = $cachePath !== null && @is_file($cachePath); if ($isCached) { return [ 'url' => $thumbUrl, 'isFinal' => true, 'thumbUrl' => $thumbUrl, ]; } // Not cached: return placeholder return [ 'url' => self::getPlaceholderUrl($width, $height, $placeholderId), 'isFinal' => false, 'thumbUrl' => $thumbUrl, ]; } /** * Build the file.php URL for a thumbnail. * * @param string $rootPath Root filesystem path * @param string $localPath Local path relative to root * @param string $pageId Page ID for ACL check * @param int $width Width * @param int $height Height * @param int $quality JPEG quality * @return string Complete URL to file.php with thumbnail parameters */ protected static function buildThumbnailUrl( string $rootPath, string $localPath, string $pageId, int $width, int $height, int $quality ): string { $params = [ 'root' => $rootPath, 'file' => $localPath, 'id' => $pageId, 'thumb' => 1, 'w' => $width, 'h' => $height, 'q' => $quality, ]; return DOKU_BASE . 'lib/plugins/luxtools/file.php?' . http_build_query($params, '', '&'); } /** * Compute the expected thumbnail cache path. * * Mirrors the hashing scheme in file.php so we can detect whether a thumb * already exists and can be used immediately. * * @param string $path Full filesystem path to the image * @param int $w Width * @param int $h Height * @param int $q Quality (JPEG) * @return string|null Path to cached thumbnail, or null if unavailable */ public static function getCachePath(string $path, int $w, int $h, int $q = 80): ?string { if ($path === '' || !is_file($path)) return null; $mtime = @filemtime($path); if ($mtime === false) return null; // Decide output format the same way file.php does try { [, $mime,] = mimetype($path, false); } catch (\Throwable $e) { return null; } if (!is_string($mime) || !str_starts_with($mime, 'image/')) return null; $dstFormat = ($mime === 'image/png' || $mime === 'image/gif') ? 'png' : 'jpg'; global $conf; if (!isset($conf['cachedir']) || !is_string($conf['cachedir']) || trim($conf['cachedir']) === '') return null; $hash = sha1($path . '|' . $mtime . '|w=' . $w . '|h=' . $h . '|q=' . $q . '|f=' . $dstFormat); $sub = substr($hash, 0, 2); $cacheDir = rtrim($conf['cachedir'], '/'); return $cacheDir . '/luxtools/thumbs/' . $sub . '/' . $hash . '.' . $dstFormat; } /** * Get placeholder image URL. * * @param int $width Desired width * @param int $height Desired height * @param string|null $placeholderId Optional MediaManager ID for custom placeholder * @return string Placeholder URL */ public static function getPlaceholderUrl(int $width, int $height, ?string $placeholderId = null): string { $placeholderUrl = DOKU_BASE . 'lib/images/blank.gif'; if ($placeholderId !== null && $placeholderId !== '' && function_exists('ml')) { $placeholderUrl = ml($placeholderId, ['w' => $width, 'h' => $height], true, '&'); } return $placeholderUrl; } /** * Determine the initial image source and data attributes for lazy thumbnail loading. * * Returns placeholder info if thumbnail needs to be loaded, or the actual * thumbnail URL if it's already cached. * * @param string $imagePath Full filesystem path to the image * @param string $thumbUrl URL to the thumbnail * @param int $width Width * @param int $height Height * @param int $quality Quality (JPEG) * @param string|null $placeholderId Optional MediaManager ID for custom placeholder * @return array ['src' => string, 'dataThumbAttr' => string] */ public static function getDisplayInfo( string $imagePath, string $thumbUrl, int $width, int $height, int $quality = 80, ?string $placeholderId = null ): array { $thumbCachePath = self::getCachePath($imagePath, $width, $height, $quality); if ($thumbCachePath !== null && @is_file($thumbCachePath)) { // Thumbnail exists: display it immediately return [ 'src' => $thumbUrl, 'dataThumbAttr' => '', ]; } // Thumbnail doesn't exist: show placeholder and lazy-load $placeholderUrl = self::getPlaceholderUrl($width, $height, $placeholderId); return [ 'src' => $placeholderUrl, 'dataThumbAttr' => ' data-thumb-src="' . hsc($thumbUrl) . '"', ]; } }