let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .camera
imagePickerController.delegate = self
self.present(imagePickerController, animated: true)
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
Task {
do {
try await viewModel.savePhoto(info)
} catch {
DispatchQueue.main.async {
print(error.localizedDescription)
}
}
}
// 카메라 창 닫기
dismiss(animated: true)
}
}
UIImage 클래스는 메타데이터를 가지고 있지 않기 때문에
Data 형식으로 바꾼 후 메타데이터를 write 해준다
HEIC가 JPEG보다 압축 성능이 좋다고 해서 HEIC로 했다
https://support.apple.com/en-gb/116944
아이폰 7 이후로는 HEIC를 지원하기 때문에 24년 7월 기준으로는 문제 없을 것
fileprivate extension UIImage {
func heif(with metadata: [String: Any]) -> Data? {
guard let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, "public.heic" as CFString, 1, nil),
let cgImage = cgImage else { return nil }
CGImageDestinationAddImage(destination, cgImage, metadata as CFDictionary)
CGImageDestinationFinalize(destination)
return mutableData as Data
}
}
func savePhoto(_ info: [UIImagePickerController.InfoKey : Any]) async throws {
guard let originalImage = info[.originalImage] as? UIImage else { throw SavePhotoError.noImage }
let imageMetadata = info[.mediaMetadata] as? [String: Any]
do {
try await saveImageToPhotos(image: originalImage, metadata: imageMetadata)
} catch {
throw error
}
}
private func saveImageToPhotos(image: UIImage, metadata: [String: Any]?) async throws {
return try await withCheckedThrowingContinuation { continuation in
PHPhotoLibrary.shared().performChanges({
if let metadata = metadata,
let imageInHEIFWithMetaData = image.heif(with: metadata) {
let request = PHAssetCreationRequest.forAsset()
request.addResource(with: .photo, data: imageInHEIFWithMetaData, options: nil)
} else {
PHAssetCreationRequest.creationRequestForAsset(from: image)
}
}, completionHandler: { success, error in
if success {
continuation.resume()
} else if let error = error {
continuation.resume(throwing: error)
}
})
}
}
카메라 | 갤러리 |
---|---|