Hello everyone,
I’m working on an iOS app that fetches videos from the "Recently Deleted" album using the Photos framework in Swift. However, I’m unable to fetch any videos, even though the "Recently Deleted" album contains 233 items (including videos), as seen in the Photos app.
Environment:
iOS Version: 18.3.1
Xcode Version: 16.2
Swift Version: Swift 5
Device: iPhone (simulator and physical device both tested)
Photo Library Permission: "All Photos" access granted
Recently Deleted Lock: Face ID/Passcode is disabled for "Recently Deleted"
Photos and Imaging
RSS for tagIntegrate still images and other forms of photography into your apps.
Posts under Photos and Imaging tag
80 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello everyone,
I am looking for a solution to programmatically, e.g. using AppleScript to import photos into the Photos library on MacOS and also push them to the shared library, like it can be done using the standard GUI of the Photos application.
Maybe it is not possible using AppleScript, but using a short Swift script and PhotoKit, I do not not know.
Any help is appreciated!
Thomas
I want to create a Live Photo. The project includes a .jpg image and a .mov video (2 seconds). I am sure they are correct.
Two permissions in xcode have been added:
Privacy - Photo Library Usage Description
Privacy - Photo Library Additions Usage Description Simulate: iphone 16, ios 18.3
The codes in ContentView.swift :
private func saveLivePhoto(imageURL: URL, videoURL: URL, completion: @escaping (Bool, Error?) -> Void) {
PHPhotoLibrary.shared().performChanges {
let creationRequest = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions()
options.shouldMoveFile = false
creationRequest.addResource(with: .photo, fileURL: imageURL, options: options)
creationRequest.addResource(with: .pairedVideo, fileURL: videoURL, options: options)
} completionHandler: { success, error in
DispatchQueue.main.async {
print(error)
completion(success, error)
}
}
}
guard let imageURL = Bundle.main.url(forResource: "livephoto", withExtension: "jpeg"),
let videoURL = Bundle.main.url(forResource: "livephoto", withExtension: "mov") else {
showAlertMessage(title: "error", message: "cant find Live Photo ")
return
}
print("imageURL: \(imageURL)")
print("videoURL: \(videoURL)")
saveLivePhoto(imageURL: imageURL, videoURL: videoURL) { success, error in
if success {
xxxxx
} else {
xxxxx
}
}
Really need help, thanks
I want to create a Live Photo. The project includes a .jpg image and a .mov video (2 seconds).
Two permissions in xcode have been added:
Privacy - Photo Library Usage Description
Privacy - Photo Library Additions Usage Description
Simulate: iphone 16, ios 18.3
The codes in ContentView.swift :
private func saveLivePhoto(imageURL: URL, videoURL: URL, completion: @escaping (Bool, Error?) -> Void) {
PHPhotoLibrary.shared().performChanges {
let creationRequest = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions()
options.shouldMoveFile = false
creationRequest.addResource(with: .photo, fileURL: imageURL, options: options)
creationRequest.addResource(with: .pairedVideo, fileURL: videoURL, options: options)
} completionHandler: { success, error in
DispatchQueue.main.async {
print(error)
completion(success, error)
}
}
}
guard let imageURL = Bundle.main.url(forResource: "livephoto", withExtension: "jpeg"),
let videoURL = Bundle.main.url(forResource: "livephoto", withExtension: "mov") else {
showAlertMessage(title: "error", message: "cant find Live Photo ")
return
}
print("imageURL: \(imageURL)")
print("videoURL: \(videoURL)")
saveLivePhoto(imageURL: imageURL, videoURL: videoURL) { success, error in
if success {
xxxxx
} else {
xxxxx
}
}
Really need help, thanks
Hey,
I have a camera app that captures a ProRaw photo and then runs a few Core Image filters before saving it to the device as a HEIC. However I'm finding that capturing at 48MP is rather slow. Testing a minimal pipeline on an iPhone 16 Pro:
Shutter press => file received in output: 1.2 ~ 1.6s
CIRawFilter created using photo file representation then rendered to context, without any filters: 0.8s ~ 1s
Saving to device ~0.15s
Is this the expected time for capturing processing? The native camera app seems to save the images within half a second. I'm using QualityPrioritization.balanced and the highest resolution available which is 48MP.
Would using the CIRawFilter with the pixelBuffer from the photo output be faster? I tried it but couldn't get it to output an image. Are there any other things I could try to speed this up? Is it possible to capture at 24MP instead?
Thanks,
Alex
iOS 18.4 - iPhone 14 Pro Max - open a photo with a face - click on info button and there is no face icon. Also there is no option to add a name to a face. Restart of iPhone didn’t help. Also this small icon of recognized face that should be on each photo with a face- disappeared from old photos.
Hi,
I'm using Core Graphics to load a .DNG photo shot by a Leica Q3 camera.
The photo is shot in portrait, however the embedded preview is rotated 90 degrees to landscape.
I load the photo like this:
let options = [kCGImageSourceDecodeRequest: kCGImageSourceDecodeToHDR] as CFDictionary
let source = CGImageSourceCreateWithData(data as CFData, nil)
let cgimage = CGImageSourceCreateImageAtIndex(source, 0, options)
let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString : Any]
When doing this I can see that the orientation property is 1 indicating that the orientation is 'Up', which it isn't.
If I don't specify the kCGImageSourceDecodeToHDR option (eseentially setting options to nil) - the orientation property is 8 (rotated 90 degrees).
What puzzles me is that a chang to the CGImageSourceCreateImageAtIndex call can have an influence on that latter call to CGImageSourceCopyPropertiesAtIndex ?
I would expect these to work independently?
Cheers
Thomas
I want to modify the photo's exif information, which means putting the original image in through CGImageDestinationAddImageFromSource, and then adding the modified exif information to a place called properties.
Here is the complete process:
static func setImageMetadata(asset: PHAsset, exif: [String: Any]) {
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { (adjustmentData) -> Bool in
return true
}
asset.requestContentEditingInput(with: options, completionHandler: { input, map in
guard let inputNN = input else {
return
}
guard let url = inputNN.fullSizeImageURL else {
return
}
let output = PHContentEditingOutput(contentEditingInput: inputNN)
let adjustmentData = PHAdjustmentData(formatIdentifier: AppInfo.appBundleId(), formatVersion: AppInfo.appVersion(), data: Data())
output.adjustmentData = adjustmentData
let outputURL = output.renderedContentURL
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil) else {
return
}
guard let dest = CGImageDestinationCreateWithURL(outputURL as CFURL, UTType.jpeg.identifier as CFString, 1, nil) else {
return
}
CGImageDestinationAddImageFromSource(dest, source, 0, exif as CFDictionary)
let d = CGImageDestinationFinalize(dest)
// d is true, and I checked the content of outputURL, image has been write correctly, it could be convert to UIImage and image is ok.
PHPhotoLibrary.shared().performChanges {
let changeReq = PHAssetChangeRequest(for: asset)
changeReq.contentEditingOutput = output
} completionHandler: { succ, err in
if !succ {
print(err) // 3303 here, always!
}
}
})
}
I am trying to recreate the iOS Messages app photo selection UI, where a PHPickerViewController is displayed half screen, with the message text field and a scrolling photo viewer on top. I have that UI mostly working, but cannot figure out how to allow a user to remove an image from my scrolling photo viewer (just like in the iOS Messages app).
When the picker is initially displayed, I can show selected images using the preselectedAssetIdentifiers. However, if the user taps the "x" to remove an image from the scrolling photo viewer, there is no way that I have found to update that selection in the picker.
I can dismiss/show a new picker with the animated property set to false, but that creates a very apparent bounce in the screen. Are there any ways I am missing to accomplish this?
Here is what I have so far:
Is there a suitable
UTType type to satisfy the need to pick up only SpatialVideo in UIDocumentPickerViewController?
I already know that PHPickerFilter in PHPickerViewController can do this, but not in UIDocumentPickerViewController.
Our app needs to adapt both of these ways to pick spatial videos
So is there anything that I can try in UIDocumentPickerViewController to fulfill such picker functionality?
Topic:
Spatial Computing
SubTopic:
General
Tags:
Files and Storage
Photos and Imaging
PhotoKit
visionOS
I'm getting the following error in my SwiftUI code:
"Main actor-isolated property 'avatarImage' can not be referenced from a Sendable closure"
I don't understand how to fix it.
This happens in the following code:
You can copy-paste this into an empty project and make sure to have Swift 6 enabled under the Build Settings > Swift Language Version
import PhotosUI
import SwiftUI
public struct ContentView: View {
@State private var avatarItem: PhotosPickerItem?
@State private var avatarImage: Image?
@State private var avatarData: Data?
public var body: some View {
VStack(spacing: 30) {
VStack(alignment: .center) {
PhotosPicker(selection: $avatarItem, matching: .images) {
if let avatarImage {
avatarImage
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.foregroundColor(.gray)
.background(.white)
.clipShape(Circle())
.opacity(0.75)
.overlay {
Image(systemName: "pencil")
.font(.title)
.shadow(radius: 5)
}
} else {
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 100)
.foregroundColor(.gray)
.background(.white)
.clipShape(Circle())
.opacity(0.75)
.overlay {
Image(systemName: "pencil")
.font(.title)
.shadow(radius: 5)
}
}
}
}
}
.onChange(of: avatarItem) {
Task {
if let data = try? await avatarItem?.loadTransferable(
type: Data.self
) {
if let processed = processImage(data: data) {
avatarImage = processed.image
avatarData = processed.data
} else {
}
}
}
}
}
private func processImage(data: Data) -> (image: Image?, data: Data?)? {
guard let uiImage = UIImage(data: data)?.preparingForDisplay() else {
return nil
}
// Check original size
let sizeInMB = Double(data.count) / (1024 * 1024)
// If image is larger than 1MB, compress it
if sizeInMB > 1.0 {
guard let compressedData = uiImage.compress() else { return nil }
return (Image(uiImage: uiImage), compressedData)
}
return (Image(uiImage: uiImage), data)
}
}
#Preview {
ContentView()
}
public extension UIImage {
func compress(to maxSizeInMB: Double = 1.0) -> Data? {
let maxSizeInBytes = Int(
maxSizeInMB * 1024 * 1024
) // Convert MB to bytes
var compression: CGFloat = 1.0
let step: CGFloat = 0.1
var imageData = jpegData(compressionQuality: compression)
while (imageData?.count ?? 0) > maxSizeInBytes, compression > 0 {
compression -= step
imageData = jpegData(compressionQuality: compression)
}
return imageData
}
}
When picking a photo in the gallery, whatever the orientation of the original image, size is always as landscape
if let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.editedImage)] as? UIImage {
print("picked original", image.size)
For a portrait photo:
picked original (1122.0, 932.0)
For a landscape:
picked original (1124.0, 844.0)
What am I missing ?
I am on Xcode 16.2 and running a simulator for iOS 18.2. Previously, I was on Xcode 15.x and running iOS 17.4 sims. This problem did not occur for me on iOS 17.4. Sample code is as follows:
import SwiftUI
import PhotosUI
struct ContentView: View {
@StateObject var imagePicker2 = ImagePicker()
var body: some View {
ScrollView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
.background(Color.orange)
.padding(.bottom, 75)
PhotosPicker(selection: $imagePicker2.imageSelection, matching: .images, photoLibrary: .shared()) {
Label("", systemImage: "photo")
}
.font(.system(size: 55))
.padding(.bottom, 55)
if let image = imagePicker2.image {
HStack {
image
.resizable()
.frame(width:75, height:75)
.scaledToFit()
.overlay(Rectangle().stroke(Color.teal, lineWidth: 2))
}
}
}
.padding()
}
}
}
import SwiftUI
import PhotosUI
@MainActor
class ImagePicker: ObservableObject {
@Published var unableToLoad: Bool = false
@Published var image: Image?
@Published var myUIImage: UIImage?
@Published var imageSelection: PhotosPickerItem? {
didSet {
unableToLoad = false
if let imageSelection {
//.. try to convert photosPickerItem imageSelection into a uiImage
Task {
try await setImage(from: imageSelection)
}
}
}
}
func setImage(from imageSelection: PhotosPickerItem?) async throws {
do {
if let data = try await imageSelection?.loadTransferable(type: Data.self) {
print("got image data")
if let uiImage = UIImage(data: data) {
print("converted to uiImage")
self.image = Image(uiImage: uiImage)
self.myUIImage = uiImage
}
}
} catch {
print(error.localizedDescription)
unableToLoad = true
}
}
}
The image loads on the UI but I get "[ERROR] Could not create a bookmark: NSError: Cocoa 4097 "connection to service named com.apple.FileProvider" in the log every time I choose a new photo. So far, I haven't had an actual crash but others have indicated that depending on what they're doing code-wise, that some have crashed. Is this an iOS 18.x bug? Thoughts?
According to the docs:
The first time your app performs an operation that requires [photo library] authorization, the system automatically and asynchronously prompts the user for it.
(https://developer.apple.com/documentation/photokit/delivering-an-enhanced-privacy-experience-in-your-photos-app)
I.e. it's not necessary for the app to call PHPhotoLibrary.requestAuthorization.
This does seem to be what happens when my app runs on an iPhone or iPad; the prompt is shown. But when it runs on a Mac in "designed for iPad" mode, the permission dialog is not presented. Instead the code continues to see status == .notDetermined.
That's today, on macOS 15.3. It may have worked in the past.
Is anyone else seeing issues with this? Should I call requestAuthorization explicitly? (Would that actually work?)
Hello, I'm wondering how to capture 24MP photos.
I'm currently testing on an iPhone 16 Pro Max. By default, the device's activeFormat supports 24MP (photo dimensions: {4032x3024, 5712x4284}). For the photoOutput, I'm setting the maxPhotoDimensions to videoDevice.activeFormat.supportedMaxPhotoDimensions.lastObject, and setting MaxPhotoQualityPrioritization to quality.
When capturing, I'm applying the same maxPhotoDimensions and photoQualityPrioritization settings from the photoOutput directly to the AVCapturePhotoSettings.
What could be the issue?
// Objective-C
// setup
[self.photoOutput setMaxPhotoQualityPrioritization:AVCapturePhotoQualityPrioritizationQuality];
CMVideoDimensions maxPhotoDimensions = [(NSValue *)videoDevice.activeFormat.supportedMaxPhotoDimensions.lastObject CMVideoDimensionsValue];
[self.photoOutput setMaxPhotoDimensions:maxPhotoDimensions];
// capturing
AVCapturePhotoSettings *photoSettings = [AVCapturePhotoSettings photoSettings];
photoSettings.maxPhotoDimensions = self.photoOutput.maxPhotoDimensions;
photoSettings.photoQualityPrioritization = self.photoOutput.maxPhotoQualityPrioritization;
[self.photoOutput capturePhotoWithSettings:photoSettings delegate:photoCaptureDelegate];
...
Hey, I'm building a camera app and I want to use the captured HDRGainMap along side the photo to do some processing with a CIFilter chain. How can this be done? I can't find any documentation any where on this, only on how to access the HDRGainMap from an existing HEIC file, which I have done successfully. For this I'm doing something like the following:
let gainmap = CGImageSourceCopyAuxiliaryDataInfoAtIndex(source, 0, kCGImageAuxiliaryDataTypeHDRGainMap)
let gainDict = NSDictionary(dictionary: gainmap)
let gainData = gainDict[kCGImageAuxiliaryDataInfoData] as? Data
let gainDescription = gainDict[kCGImageAuxiliaryDataInfoDataDescription]
let gainMeta = gainDict[kCGImageAuxiliaryDataInfoMetadata]
However I'm not sure what the approach is with a AVCapturePhoto output from a AVCaptureDevice.
Thanks!
Following WWDC 2023 "Support HDR images in your app", I'm trying to save 48-megapixel ProRAWs (taken on an iPhone 14 Pro Max) as HDR HEICs to the Photo Library. After processing the ProRAW file using CIRAWFilter, whether I use CIContext.heif10Representation() or convert to a CGImage, then UIImage, and use UIImage.heicData(), I get photos that behave oddly in the Photo Library. They appear too dark, and visibly brighten when first viewed, but more problematic is that the photos brighten a great deal more when you edit them with the Photos editor. This is the behavior when using the itur_2100_PQ color space, but itur_2100_HLG behaves similarly, except that it gets dramatically darker when edited. This behavior occurs whether CIRAWFilter.extendedDynamicRangeAmount is set to 0.0, or 2.0, or not set at all.
So what am I doing wrong? Here is a minimal iOS app -- well, just the ContentView -- that demonstrates the issue. You also need a .dng ProRAW file included in the project directory named test.dng. I'd love to include such a file, but I can't.
Be prepared for a multi-second wait when you save the photo.
import SwiftUI
import Photos
struct ContentView: View {
let context = CIContext()
let hdrColorSpace = CGColorSpace(name: CGColorSpace.itur_2100_PQ)!
var body: some View {
VStack(spacing: 100) {
Button("Save Photo From CGImage/UIImage") {
savePhotoFromUIImage()
}
Button("Save Photo From CIImage") {
savePhotoDirectFromCIImage()
}
}.padding(60)
}
//convert RAW with CIRAWFilter to CIImage, then convert to CGImage, then UIImage, then HEIF
private func savePhotoFromUIImage() {
if let ciImage = processRAW(url: Bundle.main.url(forResource:"test", withExtension: "dng")!) {
guard let outputCGImage = context.createCGImage(ciImage, from: ciImage.extent, format: .RGB10, colorSpace: hdrColorSpace) else { return }
let uiImage = UIImage(cgImage: outputCGImage)
if let heicData = uiImage.heicData() {
saveHEIFPhotoToLibrary(imageData: heicData)
} else {
print("Failed to convert UIImage to HEIC")
}
}
}
//convert RAW with CIRAWFilter to CIImage, then to HEIF
private func savePhotoDirectFromCIImage() {
if let ciImage = processRAW(url: Bundle.main.url(forResource:"test", withExtension: "dng")!) {
do {
let heif = try context.heif10Representation(of: ciImage, colorSpace: hdrColorSpace)
saveHEIFPhotoToLibrary(imageData: heif)
} catch {
print("Failed to get HEIF representation from CIContext")
}
}
}
private func processRAW(url: URL) -> CIImage? {
guard let coreRawFilter = CIRAWFilter(imageURL: url) else { return nil }
coreRawFilter.extendedDynamicRangeAmount = 2.0 //the issue persists whether this is not set, or set to 0, or set to, say, 2.0
guard let ciImage = coreRawFilter.outputImage else { return nil }
return ciImage
}
private func saveHEIFPhotoToLibrary(imageData: Data) {
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions()
creationRequest.addResource(with: .photo, data: imageData, options: options)
}) { success, error in
if let error = error {
print("Error saving photo: \(error.localizedDescription)")
} else {
print("Photo saved.")
}
}
}
}
Topic:
Media Technologies
SubTopic:
Photos & Camera
Tags:
Photos and Imaging
Core Graphics
Core Image
EDR
My visionOS requires access to users' personal photos. The trigger mechanism is: when user firstly opens a FooView, a task attached to that FooView and calling let status = PHPhotoLibrary.authorizationStatus(for: .readWrite), if the status is .notDetermined, then calling PHPhotoLibrary.requestAuthorization(for: .readWrite, handler: authCompletionHandler) to let visionOS pop out a window to request Photo access.
However, the app crashes every time when user selects Limited Access and the system try to pop out a photo library picker. And btw, I have set Prevent limited photos access alert to Yes, but it shouldn't affect the behavior here I guess.
There was a debugger message here:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Presentations are not permitted within volumetric window scenes.'
However, the window this view belongs to is a .plain style window (though there were 3D object appearing in the other view of same windowgroup)
This is my code snippet if this helps:
checkAndUpdatePhotoAuthorization is just a wrapper of PHPhotoLibrary.authorizationStatus(for: .readWrite)
private func checkAndUpdatePhotoAuthorization() -> PHAuthorizationStatus {
let currentStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
switch currentStatus {
case .authorized:
print("Photo library access authorized.")
isPhotoGalleryAuthorized = true
isPhotoGalleryLimited = false
isPhotoGalleryAccessRestricted = false
isPhotoGalleryDetermined = true
case .limited:
print("Photo library access limited.")
isPhotoGalleryLimited = true
isPhotoGalleryAuthorized = false
isPhotoGalleryAccessRestricted = false
isPhotoGalleryDetermined = true
case .notDetermined:
isPhotoGalleryDetermined = false
print("Photo library access not determined.")
case .denied:
print("Photo library access denied.")
isPhotoGalleryAuthorized = false
isPhotoGalleryLimited = false
isPhotoGalleryAccessRestricted = false
showSettingsAlert = true
isPhotoGalleryDetermined = true
case .restricted:
print("Photo library access restricted.")
isPhotoGalleryAuthorized = false
isPhotoGalleryLimited = false
isPhotoGalleryAccessRestricted = true
showPhotoAuthExplainationAlert = true
isPhotoGalleryDetermined = true
@unknown default:
print("Photo library Unknown authorization status.")
isPhotoGalleryAuthorized = false
isPhotoGalleryLimited = false
isPhotoGalleryAccessRestricted = false
isPhotoGalleryDetermined = true
}
return currentStatus
}
And then FooView attaches task to fire up checkAndUpdatePhotoAuthorization()
var body: some View {
EmptyView()
}
.task {
try? await Task.sleep(for: .seconds(1.0))
let status = self.checkAndUpdatePhotoAuthorization()
if status == .notDetermined {
DispatchQueue.main.async {
PHPhotoLibrary.requestAuthorization(for: .readWrite, handler: authCompletionHandler)
}
}
Another thing worth to mention is that SOMETIMES it won't crash when running on a debug build. But it crashes when it comes to TF.
Any other idea? Big thanks in advance
XCode version: 16.2 beta 3
VisionOS version: 2.2
for a while i had one photo widget (no special app, just the standard apple one) and it was set to shuffle to an album of pics of my bf. no problems at all. a few weeks later i added one to shuffle through an album of pics of my cat, and that one worked fine, but it made the one of my bf stop working, and it just showed a blank white widget, no error message or anything. so i removed the one of my cat hoping the one of my bf would go back to working, and it didn’t. i only have the widgets for find my, my bank, and then apps on my home screen otherwise.
What is the purpose of AdjustmentsSecondary.data included in the PHAssetResource for a cleaned-up image?
When using creationRequest.addResource, what should be set for the PHAssetResourceType?
If I set the PHAssetResourceType as follows to create an asset, it appears correctly in the camera roll. However, when attempting to edit the image in the Photos app, the app crashes:
IMG_5332.HEIC → .photo
FullSizeRender.HEIC → .fullSizePhoto
Adjustments.plist → .adjustmentData
AdjustmentsSecondary.data → .adjustmentData