ScreenshotItem を「遅延ロード対応」に進化させる
Before
|
1 2 3 4 |
struct ScreenshotItem { let cg_image: CGImage let fileURL: URL } |
After(重要)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct ScreenshotItem: Identifiable, Hashable { let id = UUID() let fileURL: URL // Sidebar用 var thumbnail: CGImage? // 必要になったら読む func loadFullImage() -> CGImage? { guard let nsImage = NSImage(contentsOf: fileURL) else { return nil } return nsImage.cgImage } } |
👉
「URLが正」
「画像はキャッシュ」
という構造になります。
サムネイル生成(超重要)
macOSではこれを使う
👉 CGImageSourceThumbnail
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import ImageIO func generateThumbnail( url: URL, maxPixel: Int = 300 ) -> CGImage? { let options: [CFString: Any] = [ kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceThumbnailMaxPixelSize: maxPixel, kCGImageSourceCreateThumbnailWithTransform: true ] guard let source = CGImageSourceCreateWithURL(url as CFURL, nil), let thumbnail = CGImageSourceCreateThumbnailAtIndex( source, 0, options as CFDictionary ) else { return nil } return thumbnail } |
- フル画像をロードしない
- メモリ効率最強
- Finderのサムネイルと同系統
起動時ロード関数(遅延ロード版)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
func loadSavedScreenshots() -> [ScreenshotItem] { let dir = AppDirectories.screenshots let urls = (try? FileManager.default.contentsOfDirectory( at: dir, includingPropertiesForKeys: [.creationDateKey], options: [.skipsHiddenFiles] )) ?? [] let sorted = urls.sorted { let a = try? $0.resourceValues(forKeys: [.creationDateKey]).creationDate let b = try? $1.resourceValues(forKeys: [.creationDateKey]).creationDate return (a ?? .distantPast) < (b ?? .distantPast) } return sorted.map { url in ScreenshotItem( fileURL: url, thumbnail: generateThumbnail(url: url) ) } } |
👉
この時点ではフル画像は1枚も読んでいない
Sidebar 側の修正(軽量化)
Before
|
1 |
Image(decorative: item.cg_image, scale: 2.0) |
After
|
1 2 3 4 5 6 |
if let thumb = item.thumbnail { Image(decorative: thumb, scale: 2.0) .resizable() .scaledToFit() .frame(height: 80) } |
👉
Sidebar は 常に軽い
選択された瞬間だけフルロード
ベース画像にする処理
|
1 2 3 4 5 6 7 8 |
Button { guard let item = selectedItem, let full = item.loadFullImage() else { return } capture_image = full base_image_update = true } |
💡
CanvasView に渡るのはフル解像度
メモリ最適化(プロっぽい一手)
サムネイルはキャッシュする
|
1 2 3 |
class ThumbnailCache { static let shared = NSCache<NSURL, CGImage>() } |
|
1 2 3 4 5 6 7 8 9 10 |
func generateThumbnail(url: URL) -> CGImage? { if let cached = ThumbnailCache.shared.object(forKey: url as NSURL) { return cached } // 生成処理 let thumb = ... ThumbnailCache.shared.setObject(thumb, forKey: url as NSURL) return thumb } |
👉
スクロールが爆速になります。
コメント