Copying/moving multi-gigabyte images with NSFileCoordinator

My app is capable of writing multi-gigabyte images. I need a way to allow the user to do something with the full-resolution images (such as AirDrop). It does not appear possible to write the image to Photos since there may not be enough memory to read the whole image in RAM and as far as I can tell PhotoKit allows readonly access.

With UIActivityViewController I am able to copy the large images with a NSFileCoordinator, but only if I use an extension of .zip or .bin for the destination URL. The file is copied, but macOS thinks they are archives and not an image. After the file has been copied, changing the extension to .jpg on the Mac allows the copied image to be used, but that is less than an ideal user experience.

Zipping the image (that is already compressed) is not a viable solution since the whole image would need to be read to zip it, which may exceed the amount of memory available. Not to mention it is a total waste of time/power consumption. How can I allow a user to copy multi-gigabyte images from my app, and ideally with UIActivityViewController?

Here is the code that allows the image to be copied. If I don't use .zip or .bin for the destination URL, the image isn't copied, nothing happens, no errors reported.

func copyImage() {
    
    let fm = FileManager.default
    var archiveUrl: URL?
    var error: NSError?
    let imageProductURL = TDTDeviceUtilites.getDocumentUrl(
                          forFileName: "hugeImage.jpg")
    
    let coordinator = NSFileCoordinator()

    coordinator.coordinate(readingItemAt: imageProductURL, 
                 options: [.forUploading],
                 error: &error) { (zipUrl) in
        let tmpUrl = try! fm.url(
            for: .itemReplacementDirectory,
            in: .userDomainMask,
            appropriateFor: zipUrl,
            create: true
        ).appendingPathComponent("hugeImage.jpg.zip")
        try! fm.moveItem(at: zipUrl, to: tmpUrl)
        archiveUrl = tmpUrl
    }

    if let url = archiveUrl {
        let avc = UIActivityViewController(activityItems: [url],
                                     applicationActivities: nil)
        present(avc, animated: true)
        
    } else {
        print(error)
    }
    
}

There appear to be several different issues at play here.

What are you trying to do with the code? Are you trying to allow the user to share an image, or add a photo to the photo library?

What happens when you don’t append a .zip extension? What is the failure mode?

As I mentioned, I need a way for the user to save multi-gigabyte images that are too big to be used with UIKit. Like the ability to copy the full resolution image with AirDrop.

I wish the user could use the standard "More actions" with the full resolution image, but it may be too big to use a UIImage etc. So when images larger than the largest possible UIImage, there will be a way to copy the full res image, and standard sharing options for the thumbnail image.

As I mentioned nothing happens without the .zip or .bin extension and no errors reported. It just doesn't do anything. Interestingly, if I make the app's Documents available in Files, Files does the same thing - it just silently fails trying to do anything with the image, but it works if the image has a .zip or .bin extension.

By the way, I have not been able to find out the largest supported pixel dimensions for UIImages, and would be helpful to know. I can do trial and error, but I don't know if they might have different supported maximum sizes based on particular devices.

Like if try to load a 50K image (1.8 billion pixels) as a UIImage on a M1 iPad Pro, it crashes. The compressed image is about 1GB. Larger images are supported.

Copying/moving multi-gigabyte images with NSFileCoordinator
 
 
Q