Search code examples
iosswiftimageurlcloudkit

How to get URL from UIImage?


I have an iOS app in which there are 2 ways the user can get a picture:

  1. Select it from photos library (UIImagePickerController)

  2. Click it from a custom made camera

Here is my code for clicking the image from a custom camera (this is within a custom class called Camera, which is a subclass of UIView)

func clickPicture(completion:@escaping (UIImage) -> Void) {

    guard let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo)  else { return }

    videoConnection.videoOrientation = .portrait
    stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in

        guard let buffer = sampleBuffer else { return }

        let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
        let dataProvider = CGDataProvider(data: imageData! as CFData)
        let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)

        let image = UIImage(cgImage: cgImageRef!, scale: 1, orientation: .right)

        completion(image)


    })
}

Here is how I click the image within the ViewController:

@IBAction func clickImage(_ sender: AnyObject) {
    cameraView.clickPicture { (image) in
        //use "image" variable
    }
}

Later, I attempt to upload this picture to the user's iCloud account using CloudKit. However I receive an error saying the record is too large. I then came across this SO post, which says to use a CKAsset. However, the only constructor for a CKAsset requires a URL.

Is there a generic way I can get a URL from any UIImage? Otherwise, how can get a URL from the image I clicked using my custom camera (I have seen other posts about getting a url from a UIImagePickerController)? Thanks!


Solution

  • CKAsset represents some external file (image, video, binary data and etc). This is why it requires URL as init parameter.

    In your case I would recommend to use following steps to upload large image to CloudKit:

    1. Save UIImage to local storage (e.g. documents directory).
    2. Initialize CKAsset with path to image in local storage.
    3. Upload asset to Cloud.
    4. Delete image from local storage when uploading completed.

    Here is some code:

    // Save image.
    let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
    let filePath = "\(path)/MyImageName.jpg"
    
    UIImageJPEGRepresentation(image, 1)!.writeToFile(filePath, atomically: true)
    
    let asset = CKAsset(fileURL: NSURL(fileURLWithPath: filePath)!)
    // Upload asset here.
    
    // Delete image.
    do {
        try FileManager.default.removeItem(atPath: filePath)
    } catch {
        print(error)
    }