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
)