Skip to main content

Get thumbnailimage working

ID
bff1a60
date
2023-06-08 09:37:49+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
d76b475
message
Get thumbnailimage working
changed files
5 files, 67 additions, 100 deletions

Changed files

BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj (24682) → BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj (24688)

diff --git a/BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj b/BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj
index 49ef119..80f28a6 100644
--- a/BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj
+++ b/BlinkReviewer/BlinkReviewer.xcodeproj/project.pbxproj
@@ -14,7 +14,7 @@
 		94D751022A31A798005859E7 /* BlinkReviewerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D751012A31A798005859E7 /* BlinkReviewerTests.swift */; };
 		94D7510C2A31A798005859E7 /* BlinkReviewerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7510B2A31A798005859E7 /* BlinkReviewerUITests.swift */; };
 		94D7510E2A31A798005859E7 /* BlinkReviewerUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7510D2A31A798005859E7 /* BlinkReviewerUITestsLaunchTests.swift */; };
-		94D7511C2A31A7B1005859E7 /* ThumbnailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7511B2A31A7B1005859E7 /* ThumbnailItem.swift */; };
+		94D7511C2A31A7B1005859E7 /* ThumbnailImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7511B2A31A7B1005859E7 /* ThumbnailImage.swift */; };
 		94D7511E2A31B243005859E7 /* PreviewImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7511D2A31B243005859E7 /* PreviewImage.swift */; };
 		94D751202A31B53E005859E7 /* AlbumInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D7511F2A31B53E005859E7 /* AlbumInfo.swift */; };
 		94D751222A31BD8E005859E7 /* PhotoReviewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94D751212A31BD8E005859E7 /* PhotoReviewer.swift */; };
@@ -50,7 +50,7 @@
 		94D751072A31A798005859E7 /* BlinkReviewerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BlinkReviewerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		94D7510B2A31A798005859E7 /* BlinkReviewerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlinkReviewerUITests.swift; sourceTree = "<group>"; };
 		94D7510D2A31A798005859E7 /* BlinkReviewerUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlinkReviewerUITestsLaunchTests.swift; sourceTree = "<group>"; };
-		94D7511B2A31A7B1005859E7 /* ThumbnailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailItem.swift; sourceTree = "<group>"; };
+		94D7511B2A31A7B1005859E7 /* ThumbnailImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailImage.swift; sourceTree = "<group>"; };
 		94D7511D2A31B243005859E7 /* PreviewImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewImage.swift; sourceTree = "<group>"; };
 		94D7511F2A31B53E005859E7 /* AlbumInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumInfo.swift; sourceTree = "<group>"; };
 		94D751212A31BD8E005859E7 /* PhotoReviewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoReviewer.swift; sourceTree = "<group>"; };
@@ -144,7 +144,7 @@
 		94D7511A2A31A7A6005859E7 /* Views */ = {
 			isa = PBXGroup;
 			children = (
-				94D7511B2A31A7B1005859E7 /* ThumbnailItem.swift */,
+				94D7511B2A31A7B1005859E7 /* ThumbnailImage.swift */,
 				94D7511D2A31B243005859E7 /* PreviewImage.swift */,
 				94D7511F2A31B53E005859E7 /* AlbumInfo.swift */,
 				94D751212A31BD8E005859E7 /* PhotoReviewer.swift */,
@@ -290,7 +290,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				94D7511C2A31A7B1005859E7 /* ThumbnailItem.swift in Sources */,
+				94D7511C2A31A7B1005859E7 /* ThumbnailImage.swift in Sources */,
 				94D750F22A31A796005859E7 /* ContentView.swift in Sources */,
 				94D7512B2A31D6AC005859E7 /* AssetHelpers.swift in Sources */,
 				94D7511E2A31B243005859E7 /* PreviewImage.swift in Sources */,

BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (878) → BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (2426)

diff --git a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
index 01ef8fe..80ba71a 100644
--- a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
+++ b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
@@ -7,6 +7,7 @@
 
 import Foundation
 import Photos
+import SwiftUI
 
 /// Returns a list of all the images in the Photos Library.
 func getAllPhotos() -> [PHAsset] {
@@ -33,4 +34,49 @@ extension PHAsset {
         
         return result
     }
+    
+    private func getImageForSize(size: CGSize) -> NSImage {
+        // This implementation is based on code in a Stack Overflow answer
+        // by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022
+
+        let options = PHImageRequestOptions()
+        
+        // do I still need this?
+        options.isSynchronous = true
+
+        // If i don't set this value, then sometimes I get an error like
+        // this in the `info` variable:
+        //
+        //      Error Domain=PHPhotosErrorDomain Code=3164 "(null)"
+        //
+        // This means that the asset is in the cloud, and by default Photos
+        // isn't allowed to download assets here.  Apple's documentation
+        // suggests adding this option as the fix.
+        //
+        // See https://developer.apple.com/documentation/photokit/phphotoserror/phphotoserrornetworkaccessrequired
+        options.isNetworkAccessAllowed = true
+
+        var image = NSImage()
+        
+        PHCachingImageManager()
+            .requestImage(
+                for: self,
+                targetSize: size,
+                contentMode: .aspectFill,
+                options: options,
+                resultHandler: { (result, info) -> Void in
+                    image = result!
+                }
+            )
+
+        return image
+    }
+    
+    func getThumbnail() -> NSImage {
+        return getImageForSize(size: CGSize(width: 70, height: 70))
+    }
+    
+    func getImage() -> NSImage {
+        return getImageForSize(size: PHImageManagerMaximumSize)
+    }
 }

BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (2024) → BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (2024)

diff --git a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
index 71e86e2..6b97356 100644
--- a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
@@ -21,10 +21,10 @@ struct PhotoReviewer: View {
                         // TODO: placeholder images for start/end
                         // TODO: Allow tapping thumbnails to jump to that
                         ForEach(assets, id: \.localIdentifier) { asset in
-                            ThumbnailItem(thumbnail: asset.getThumbnail(), isSelected: assets[selectedAssetIndex].localIdentifier == asset.localIdentifier)
+                            ThumbnailImage(thumbnail: asset.getThumbnail(), isSelected: assets[selectedAssetIndex].localIdentifier == asset.localIdentifier)
                         }
                     }.padding()
-                }.frame(height: 100)
+                }.frame(height: 70)
                     .onChange(of: selectedAssetIndex, perform: { newIndex in
                         withAnimation {
                             proxy.scrollTo(assets[newIndex].localIdentifier, anchor: .center)

BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift (3933) → BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift (752)

diff --git a/BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift b/BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift
index 3c84d55..c4444c4 100644
--- a/BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/PreviewImage.swift
@@ -8,96 +8,6 @@
 import Photos
 import SwiftUI
 
-extension PHAsset {
-    func getThumbnail() -> NSImage {
-        // This implementation is based on code in a Stack Overflow answer
-        // by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022
-
-        let options = PHImageRequestOptions()
-        
-        // do I still need this?
-        options.isSynchronous = true
-
-        // If i don't set this value, then sometimes I get an error like
-        // this in the `info` variable:
-        //
-        //      Error Domain=PHPhotosErrorDomain Code=3164 "(null)"
-        //
-        // This means that the asset is in the cloud, and by default Photos
-        // isn't allowed to download assets here.  Apple's documentation
-        // suggests adding this option as the fix.
-        //
-        // See https://developer.apple.com/documentation/photokit/phphotoserror/phphotoserrornetworkaccessrequired
-        options.isNetworkAccessAllowed = true
-
-        var image = NSImage()
-        
-        PHCachingImageManager()
-            .requestImage(
-                for: self,
-                targetSize: CGSize(width: 70, height: 70),
-                contentMode: .aspectFill,
-                options: options,
-                resultHandler: { (result, info) -> Void in
-                    image = result!
-                }
-            )
-
-        return image
-    }
-    
-    func getImage() -> NSImage {
-        // This implementation is based on code in a Stack Overflow answer
-        // by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022
-
-        let options = PHImageRequestOptions()
-        options.isSynchronous = true
-
-        // If i don't set this value, then sometimes I get an error like
-        // this in the `info` variable:
-        //
-        //      Error Domain=PHPhotosErrorDomain Code=3164 "(null)"
-        //
-        // This means that the asset is in the cloud, and by default Photos
-        // isn't allowed to download assets here.  Apple's documentation
-        // suggests adding this option as the fix.
-        //
-        // See https://developer.apple.com/documentation/photokit/phphotoserror/phphotoserrornetworkaccessrequired
-        options.isNetworkAccessAllowed = true
-
-        var image = NSImage()
-        
-        let start = DispatchTime.now()
-        var elapsed = start
-
-        func printElapsed(_ label: String) -> Void {
-          let now = DispatchTime.now()
-
-          let totalInterval = Double(now.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000
-          let elapsedInterval = Double(now.uptimeNanoseconds - elapsed.uptimeNanoseconds) / 1_000_000_000
-
-          elapsed = DispatchTime.now()
-
-          print("Time to \(label):\n  \(elapsedInterval) seconds (\(totalInterval) total)")
-        }
-        
-        PHCachingImageManager()
-            .requestImage(
-                for: self,
-                targetSize: PHImageManagerMaximumSize,
-                contentMode: .aspectFit,
-                options: options,
-                resultHandler: { (result, info) -> Void in
-                    image = result!
-                }
-            )
-        
-        printElapsed("getting image \(self.localIdentifier)")
-
-        return image
-    }
-}
-
 struct PreviewImage: View {
     var asset: PHAsset
     

BlinkReviewer/BlinkReviewer/Views/ThumbnailItem.swift (839) → BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift (1271)

diff --git a/BlinkReviewer/BlinkReviewer/Views/ThumbnailItem.swift b/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
similarity index 72%
rename from BlinkReviewer/BlinkReviewer/Views/ThumbnailItem.swift
rename to BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
index 81ecb80..2eed657 100644
--- a/BlinkReviewer/BlinkReviewer/Views/ThumbnailItem.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
@@ -7,7 +7,11 @@
 
 import SwiftUI
 
-struct ThumbnailItem: View {
+/// Renders a square thumbnail for an image.
+///
+/// The image will be expanded to fill the square, and may be clipped
+/// if the original aspect ratio isn't square.
+struct ThumbnailImage: View {
     var thumbnail: NSImage
     var isSelected: Bool
     
@@ -18,8 +22,15 @@ struct ThumbnailItem: View {
     var body: some View {
         Image(nsImage: thumbnail)
             .resizable()
-            // Note: order of properties is important, frame before aspectRatio otherwise breaks!
-            // only in running app, not SwiftUI preview \_/
+            // Note: it's taken several attempts to get this working correctly;
+            // it behaves differently in the running app to the SwiftUI preview.
+            //
+            // Expected properties:
+            //
+            //    - Thumbnails are square
+            //    - Thumbnails are expanded to fill the square, but they prefer
+            //      to crop rather than stretch the image
+            //
             .scaledToFill()
             .frame(width: size, height: size, alignment: .center)
             .clipped()
@@ -28,7 +39,7 @@ struct ThumbnailItem: View {
 
 struct ThumbnailItem_Previews: PreviewProvider {
     static var previews: some View {
-        ThumbnailItem(
+        ThumbnailImage(
             thumbnail: NSImage(named: "IMG_5934")!,
             isSelected: true
         )