get Image from PHAsset issue to detect updates on images - swift4

I'm currently managing a PHAsset with multiple Pictures (from an Album my application is creating), I'm able to display it without any problem.
For each picture of my PHAsset, I'm calculating the hash of each pictures in my app.
But If I'm modifying the picture out of my app (through the Photos, I'm changing the color of the picture for example) I'm not able to detect the update, if I'm calculating the hash one more time of the PHAsset pictures while my app is resumed, the update is not detected, the hashes remains the same...
Here is the code to get image from PHAsset:
var img: UIImage?
let manager = PHImageManager.default()
let options = PHImageRequestOptions()
options.version = .original
options.isSynchronous = true
manager.requestImageData(for: asset, options: options) { (data, _, _, _) in
if let data = data{
img = UIImage(data: data)
}
}
return img
I'm using this function while adding the picture (to calculate the hash), and when I need to check the hash of the PHasset's pictures, I'm retrieving the PHAssetCollection by using
let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
but no changes are detected...may be I need to ask for a refresh of the PHAssetCollection to retrieve the changes on the pictures ?
Am I missing something ?
Just to be clear, I'm calculating the hash of the Image with the following:
//function described just above
let img = getSavedImageFromPHAsset(asset: myAsset)!
let img_hash = img.sha256()
//I'm comparing the hashes with this value
func sha256(data: Data) -> Data {
var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
data.withUnsafeBytes {messageBytes in
CC_SHA256(messageBytes, CC_LONG(data.count), digestBytes)
}
}
return digestData
}
I assumed that as soon as an image linked to the PHAsset has been changed, I'm able to detect its modification (I can see the picture updated on my app's screen, but hash calculated is still the same)

Try the following:
options.version = .current
instead of
options.version = .original
Your code will always return the original, unedited photo/video. .current returns the same photo that you see in the iOS Photos App.

Related

Using VNRecognizeTextRequest on image drawn in UIImageView returns empty results

I have an UIImageView in which I draw handwritten text, using UIGraphicsBeginImageContext to create the bitmap image.
I pass this image to an OCR func:
func ocrText(onImage: UIImage?) {
let request = VNRecognizeTextRequest { request, error in
guard let observations = request.results as? [VNRecognizedTextObservation] else {
fatalError("Received invalid observations") }
print("observations", observations.count) // count is 0
for observation in observations {
if observation.topCandidates(1).isEmpty {
continue
}
}
} // end of request
request.recognitionLanguages = ["fr"]
let requests = [request]
DispatchQueue.global(qos: .userInitiated).async {
let ocrGroup = DispatchGroup()
guard let img = onImage?.cgImage else { return }
crGroup.enter()
let handler = VNImageRequestHandler(cgImage: img, options: [:])
try? handler.perform(requests)
ocrGroup.leave()
crGroup.wait()
}
}
Problem is that observations is an empty array.
But, If I save UIImage to the photo album:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
and read back image from the album with imagePicker and pass this image to ocrText, it works.
So it seems there is a format change to the image (or metadata?) when saved to album and that VNRecognizer needs those data.
Is there a way to change directly the original bitmap image format, without going through the storage on photo album ?
Or am I missing something in the use of VNRecognizeTextRequest ?
I finally found a way to get it.
I save the image to a file as jpeg and read the file back.
This didn't work with png, but works with jpeg.

Get Filename From PHAsset swift 5 IOS13

My Question is how we get file Name From PHAsset Which Are Picked By gallery
var allSmallPic: [PHAsset] = []
PHImageManager.default().requestImage(for: allSmallPic[indexPath.row], targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: nil) { (image, info) in
cell.ImageVieww.image = image
cell.Labell.text = "\(String(describing: info!))"
print(info!)
}
let resource1 = PHAssetResource.assetResources(for:self.allSmallPic[indexPath.row])
print("Get resources\(resource1)")
cell.Labell.text = resource1[0].originalFilename
As you Know PHAsset is representation of an image, video, or Live Photo in the Photos library.
So I want to show the file names into my tableViewCell Like this
when no results found i'm start read documentations and i found PHAssetResource and they help me to Get image name
let resource1 = PHAssetResource.assetResources(for:self.allSmallPic[indexPath.row])
print("Get resources\(resource1)")
cell.Labell.text = resource1[0].originalFilename
The allSmallPic is global array which store PHAsset

How to download image from iCloud without re-saving it?

I ran into a problem when trying to pick photo from gallery (app crashes when I pick image uploaded on iCloud).
So my first solution was to check if image is on device and if not, then download it from iCloud.
I used this code
let manager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = .exact
requestOptions.deliveryMode = .highQualityFormat;
// Request Image
manager.requestImageData(for: asset, options: requestOptions, resultHandler: { (data, str, orientation, info) -> Void in
// Do somethign with Image Data
})
I get imageData in this situation, but if I want to save it, it saves into new photo. So I get copy of image in Photos instead getting one original image that stores on device.
So my question is how to download image without re-saving it.
Basically I want same behaviour as in photos app (when photo is not on device, it downloads photo and save it into same picture instead creating copy of it)
I faced this issue, here is a workaround for it:
Set isNetworkAccessAllowed to false:
requestOptions.isNetworkAccessAllowed = false
That's because you need to make sure that we will not fetch it from the iCloud. At this point, if the image is not downloaded, the data in resultHandler should be nil:
manager.requestImageData(for: PHAsset(), options: requestOptions, resultHandler: { (data, str, orientation, info) -> Void in
if let fetchedData = data {
// the image is already downloaded
} else {
// the image is not downloaded...
// now what you should do is to set isNetworkAccessAllowed to true
// and make a new request to get it from iCloud.
}
})
Furthermore, you could leverage PHImageResultIsInCloudKey:
manager.requestImageData(for: PHAsset(), options: requestOptions, resultHandler: { (data, str, orientation, info) -> Void in
if let keyNSNumber = info?[PHImageResultIsInCloudKey] as? NSNumber {
if keyNSNumber.boolValue {
// its on iCloud...
// read the "keep in mind" below note,
// now what you should do is to set isNetworkAccessAllowed to true
// and make a new request.
} else {
//
}
}
})
As per mentioned in PHImageResultIsInCloudKey documentation, keep in mind that:
If true, no image was provided, because the asset data must be
downloaded from iCloud. To download the data, submit another request,
and specify true for the isNetworkAccessAllowed option.

Read Gallery Video in Custom Size

How could I get a video from Gallery(Photos) in custom format and size.
for example I want to read a video in 360p.
I used below code to get video data but apple said it doesn't guarantee to read it in lowest quality.
It's a PHAsset extension, so self refering to a PHAsset object.
var fileData: Data? = nil
let manager = PHImageManager.default()
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
options.deliveryMode = .fastFormat
manager.requestAVAsset(forVideo: self, options: options) {
(asset: AVAsset?, audioMix: AVAudioMix?, _) in
if let avassetURL = asset as? AVURLAsset {
guard let video = try? Data(contentsOf: avassetURL.url) else {
print("reading video failed")
return
}
fileData = video
}
}
There is a simple reason it can't be guaranteed: The file in 360p might not be on the device or in the cloud. So the Photos framework will deliver a format nearest to what you request. If you want exactly 360p, I would recommend you reencode the video you get from the photos framework yourself.

Swift 2 Parse and KingFisher cache images

I'm using KingFisher https://github.com/onevcat/Kingfisher
library so i can cache the images and if there is anyone familiar with it i want some hints.
So i have the following code
let myCache = ImageCache(name: recipesClass.objectId!)
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let optionInfo: KingfisherOptionsInfo = [
.DownloadPriority(0.5),
.CallbackDispatchQueue(queue),
.Transition(ImageTransition.Fade(1)),
.TargetCache(myCache)
]
if let imageFile = recipesClass[RECIPES_COVER] as? PFFile {
let URL = NSURL(string: imageFile.url!)!
cell.coverImage.kf_setImageWithURL(URL, placeholderImage: nil,
optionsInfo: optionInfo,
progressBlock: { receivedSize, totalSize in
print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
},
completionHandler: { image, error, cacheType, imageURL in
print("\(indexPath.row + 1): Finished")
})
} else {
cell.coverImage.image = UIImage(named:"logo")
}
When i first enter the View it loads normally the images with this good anymation. But i also have a refresh button which makes a query to Parse and it checks if there is any new Recipe and then it reloads the data from the collection view and it prints "Finished"
Does this means that it downloads the images again? Or it loads them from Cache??
I'm asking because it appends the images in a different way inside the cells rather than the first time that it loads.
Any idea?
P.S. what i want to do is that in each cell i want to cache the image with the object ID of each recipe so when the cell loads and it has the image cached with this unique object id, to load it from cache and not to download it.
try this code:
var imageView:UIImageView!
let mCa = ImageCache(name: "my_cache")
let imagePath = getImagePath("image url")
imageView.kf_setImageWithURL(NSURL(string: imagePath)!,placeholderImage: UIImage(named: "DefaultImageName"),optionsInfo: [.TargetCache(mCa)])