#swift #xcode #url #camera
#swift #xcode #url #камера
Вопрос:
Я пытаюсь вычислить хэш файла для JPEG
файлов (например MD5
) после съемки встроенной камерой. Я могу создать дайджест данных изображения, но это не будет совпадать с фактическим хэшем файла. Глядя на модуль Photo и его PHAsset
класс, я не вижу способа получить фактический путь к файлу (URL), который я мог бы затем передать MD5Digest
. Возможно, можно захватить файл URL
сразу после сохранения изображения на фотопленке, реализовав функцию прослушивания завершения. Кто-нибудь пробовал это раньше?
Обновлен код с помощью completionHandler, но мне все еще нужно найти URL.
@IBOutlet weak var imageHash: UILabel!
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let orgPic = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
UIImageWriteToSavedPhotosAlbum(orgPic!, self, #selector(imageSaved(_:didFinishSavingWithError:contextInfo:)), nil)
}
@objc func imageSaved(_ img: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "(img.ciImage?.url)", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
// the img.ciImage.url is "nil" unfortunately
Комментарии:
1. Привет, Ико, было бы здорово, если бы ты могла добавить какой-нибудь код, который помог бы понять проблему.
2. Хэш MD5 над данными изображения отличается от хэша файла над JPEG на фотопленке. UIImageWriteToSavedPhotosAlbum(), вероятно, удаляет некоторые данные, а затем применяет сжатие JPEG перед сохранением. Единственный способ вычислить истинный хэш файла — это найти URL-адрес файла и прочитать его примерно так: «пусть data = try Data(contentsOf: someFileURL)», затем запустить хэш, как в «пусть digest = data.md5». Мой вопрос в том, могу ли я найти URL-адрес файла, предоставив обработчик завершения в UIImageWriteToSavedPhotosAlbum (будет третьим аргументом)? Большое спасибо -Iko
Ответ №1:
Итак, ваш главный девиз — сравнить MD5 из 2 файлов изображений. Итак, вот что я попробовал, и, возможно, это поможет вам
; TLDR — файл, сохраненный в библиотеке, и фактический файл у меня не совпадали
public func saveImgToLocal(_ img: UIImage,
onComplete: @escaping () -> Void) {
var blockPlaceholder: PHObjectPlaceholder?
var changeRequest: PHAssetChangeRequest?
PHPhotoLibrary.shared().performChanges({
changeRequest = PHAssetChangeRequest.creationRequestForAsset(from: img)
blockPlaceholder = changeRequest?.placeholderForCreatedAsset
}, completionHandler: { (saved, error) in
//_saved_ is of type bool, you can use it to check whether image is saved
//Here we would fetch the asset using our saved placeholder
let fetchOptions = PHFetchOptions()
let fetchResult:PHFetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [blockPlaceholder!.localIdentifier], options: fetchOptions)
if let asset = fetchResult.firstObject {
//Method to convert asset to Actual image
self.getAsset(asset: asset)
}
onComplete()
})
}
Вот как я сохранил изображение в Local
Вот как я получил изображение от Local
func getAsset(asset: PHAsset) {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var resultImage = UIImage()
option.isSynchronous = true
manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
resultImage = result!
let url = info!["PHImageFileURLKey"] as! NSURL
//Image created using the file URL.
let image = UIImage.init(contentsOfFile: url.path!)
//I even compared the resultImage instead of the image from the file
if UIImagePNGRepresentation(image!) == UIImagePNGRepresentation(self.image!) {
print("Same image")
}
})
}
Так что, если вы просто хотите вернуть сохраненное изображение, это можно сделать, но я не уверен, сохранено ли изображение в том виде, в каком оно есть в библиотеке фотографий.
HTH 🙂
Комментарии:
1. Идеальный. Работает как по волшебству. Спасибо, что положили конец 2 дням страданий 😉
2. Спасибо 🙂 Можете ли вы принять ответ, если это поможет? Мне нужны очки:-p
Ответ №2:
Хотя опубликованный Аджинкьей Шармой код работал, я заметил, что производительность сохранения изображений на фотопленке была значительно ниже при использовании creationRequestForAsset по сравнению с UIImageWriteToSavedPhotosAlbum. Поэтому я выбрал гибридное решение. Я сохранил, используя старую функцию, затем использовал PHAsset framework для извлечения новейшего файла изображения и получения его URL. Проблема решена.
public func saveImgToLocal(_ img: UIImage) {
// significantly faster than creationRequestForAsset
UIImageWriteToSavedPhotosAlbum(img, self, #selector(imageSaved(_:didFinishSavingWithError:contextInfo:)), nil)
}
@objc func imageSaved(_ img: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.fetchLimit = 1
let fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
if let asset = fetchResult.firstObject
{
self.imageHash.text = getAsset(asset: asset)
}
}
}
func getAsset(asset: PHAsset) -> String {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var hashString = "" as String
option.isSynchronous = true
manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: option, resultHandler: {(result, info) -> Void in
let url = info!["PHImageFileURLKey"] as! NSURL
do {
let data = try Data(contentsOf: url as URL)
hashString = data.md5.rawValue
}
catch {
hashString = "Error computing hash"
}
})
return hashString
}