var body: some View {
PhotosPicker(selection: $selectedItem, matching: .any(of: [.images, .videos]), photoLibrary: .shared()){
Image(systemName: "camera.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 20)
.padding(2)
}
.onChange(of: selectedItem) { newItem in
// item size in kilobytes?
}
}
Is there a way to get the size of selectedItem
in Kilobytes?
I know how to do it by finding out the URL of the item first and then the size of it by the URL, but this is kinda a dumb workaround since the item is already selected and it's also kinda slow.
You can load the item and use the byte count.
import SwiftUI
import PhotosUI
struct PhotoFileSize: View {
@State private var selectedItem: PhotosPickerItem?
var body: some View {
PhotosPicker(selection: $selectedItem) {
Text("Selected Item")
}
.task(id: selectedItem) {
//Only run this code if there is a selected item
guard let selectedItem else {return}
do {
let result = try await selectedItem.loadTransferable(type: Data.self)
switch result {
case .none:
break
case .some(let data):
let size = Measurement(value: Double(data.count), unit: UnitInformationStorage.bytes)
print(size.converted(to: .kilobytes).formatted())
}
} catch {
print(error)
}
}
}
}
#Preview {
PhotoFileSize()
}
///PhotosPhickerItem is a struct
extension PhotosPickerItem: @unchecked Sendable {}
or get the file size without loading the item into memory but it requires additional permissions.
import SwiftUI
import PhotosUI
struct PhotoFileSize: View {
@State private var selectedItem: PhotosPickerItem?
//Required or `itemIdentifier` will be nil
let library: PHPhotoLibrary = .shared()
var body: some View {
PhotosPicker(selection: $selectedItem, photoLibrary: library) {
Text("Selected Item")
}
.task(id: selectedItem) {
//Only run this code if there is a selected item
guard let selectedItem else {return}
//Get the local identifier
guard let id = selectedItem.itemIdentifier else {return}
//Must have authorization to access the PhotoLibrary/PHAsset directly
guard await PHPhotoLibrary.requestAuthorization(for: .readWrite) == .authorized else {return}
let asset = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil).firstObject!
let resources = PHAssetResource.assetResources(for: asset)
//Get the file sizw
guard let fileSize = resources.first?.fileSize else {
return
}
print(fileSize.converted(to: .kilobytes).formatted())
}
}
}
#Preview {
PhotoFileSize()
}
extension PHAssetResource {
var fileSize: Measurement<UnitInformationStorage>? {
guard let unsignedInt64 = self.value(forKey: "fileSize") as? CLong else {return nil}
let sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64))
return .init(value: Double(sizeOnDisk), unit: .bytes)
}
}