@@ -136,6 +136,10 @@ struct RemoteThumbnail: View {
136136 }
137137 } , threshold: 0 ) )
138138 . id ( file. path) // Ensure view resets when file changes
139+ . onDisappear {
140+ image = nil
141+ gifData = nil
142+ }
139143 }
140144
141145 func overlayPlayIcon( on image: UIImage ) -> UIImage {
@@ -198,6 +202,36 @@ struct RemoteThumbnail: View {
198202 }
199203 }
200204
205+ func downsampleImage(
206+ data: Data ,
207+ maxDimension: CGFloat
208+ ) -> UIImage ? {
209+ let sourceOptions : [ CFString : Any ] = [
210+ kCGImageSourceShouldCache: false
211+ ]
212+
213+ guard let source = CGImageSourceCreateWithData ( data as CFData , sourceOptions as CFDictionary ) else {
214+ return nil
215+ }
216+
217+ let downsampleOptions : [ CFString : Any ] = [
218+ kCGImageSourceCreateThumbnailFromImageAlways: true ,
219+ kCGImageSourceThumbnailMaxPixelSize: maxDimension,
220+ kCGImageSourceCreateThumbnailWithTransform: true ,
221+ kCGImageSourceShouldCacheImmediately: true
222+ ]
223+
224+ guard let cgImage = CGImageSourceCreateThumbnailAtIndex (
225+ source,
226+ 0 ,
227+ downsampleOptions as CFDictionary
228+ ) else {
229+ return nil
230+ }
231+
232+ return UIImage ( cgImage: cgImage)
233+ }
234+
201235 private func actuallyLoadThumbnail( retryCount: Int = 0 ) {
202236 let fileName = file. name. lowercased ( )
203237 let isGIF = fileName. hasSuffix ( " .gif " )
@@ -214,7 +248,7 @@ struct RemoteThumbnail: View {
214248 if let cached = existingCache {
215249 if isGIF {
216250 GlobalThumbnailLoader . shared. finish ( filePath: file. path, image: nil , gifData: cached, failed: false )
217- } else if let img = UIImage ( data: cached) {
251+ } else if let img = downsampleImage ( data: cached, maxDimension : 320 ) {
218252 GlobalThumbnailLoader . shared. finish ( filePath: file. path, image: img, gifData: nil , failed: false )
219253 } else {
220254 // Cached data is corrupted, continue with network load
@@ -261,13 +295,18 @@ struct RemoteThumbnail: View {
261295 imageData = thumbImage. pngData ( )
262296 }
263297 if let data = imageData, advancedSettings. cacheThumbnail {
264- FileCache . shared. store (
265- for: serverURL,
266- data: data,
267- path: file. path,
268- modified: file. modified,
269- fileID: " thumb "
270- )
298+ if let img = downsampleImage ( data: data, maxDimension: Constants . maxThumbnailSize) ,
299+ let compressed = img. jpegData ( compressionQuality: Constants . thumbnailQuality) ,
300+ advancedSettings. cacheThumbnail {
301+
302+ FileCache . shared. store (
303+ for: serverURL,
304+ data: compressed,
305+ path: file. path,
306+ modified: file. modified,
307+ fileID: " thumb "
308+ )
309+ }
271310 }
272311 GlobalThumbnailLoader . shared. finish ( filePath: file. path, image: thumbImage, gifData: nil , failed: false )
273312 } catch {
@@ -298,20 +337,24 @@ struct RemoteThumbnail: View {
298337 }
299338 autoreleasepool {
300339 if advancedSettings. cacheThumbnail {
301- FileCache . shared. store (
302- for: serverURL,
303- data: data,
304- path: file. path,
305- modified: file. modified,
306- fileID: " thumb "
307- )
340+ if let img = downsampleImage ( data: data, maxDimension: Constants . maxThumbnailSize) ,
341+ let compressed = img. jpegData ( compressionQuality: Constants . thumbnailQuality) ,
342+ advancedSettings. cacheThumbnail {
343+ FileCache . shared. store (
344+ for: serverURL,
345+ data: compressed,
346+ path: file. path,
347+ modified: file. modified,
348+ fileID: " thumb "
349+ )
350+ }
308351 }
309352 if isGIF {
310353 GlobalThumbnailLoader . shared. finish ( filePath: file. path, image: nil , gifData: data, failed: false )
311- } else if let img = UIImage ( data: data) {
354+ } else if let img = downsampleImage ( data: data, maxDimension : Constants . maxThumbnailSize ) {
312355 GlobalThumbnailLoader . shared. finish ( filePath: file. path, image: img, gifData: nil , failed: false )
313356 } else {
314- let errMsg = " Failed to decode image thumbnail for file: \( file. name) — data size: \( data . count ) bytes "
357+ let errMsg = " Failed to downsample image thumbnail for file: \( file. name) "
315358 retryHandler ( retryCount: retryCount, errMsg: errMsg)
316359 }
317360 }
0 commit comments