in an ios swift application,
I am using writeImageToSavedPhotosAlbum to save a UIImage on the iphone
let assets : ALAssetsLibrary = ALAssetsLibrary()
let imgRef : CGImage = myImage!.CGImage
let orientation : ALAssetOrientation = ALAssetOrientation(rawValue: myImage!.imageOrientation.rawValue)!
assets.writeImageToSavedPhotosAlbum(imgRef, orientation: orientation, completionBlock: nil)
Is there a way I can get the saved image filename? or maybe to set it myself?
Thank you for any help
If you look at the spec of the method you're using you will see that the completion block you aren't using is of type ALAssetsLibraryWriteImageCompletionBlock, which has the parameters NSURL *assetURL, NSError *error.
So specify a completion block and you get the asset URL from which you can derive some information.
You can get the file path information using the completion block parameter. Instead of passing nil pass the block like:
assets.writeImageToSavedPhotosAlbum(imgRef, orientation: orientation, completionBlock:
{ (path:NSURL!, error:NSError!) -> Void in
println("\(path)")
})
Check the ALAssetLibrary Class Reference for more information
Related
I'm storing images and videos in a Camera Roll album using PhotoKit, and want to allow the user to share them using UIActivityViewController. If I pass UIActivityViewController a UIImage instance, it works as expected, probably because the image data is passed in memory. However, videos need to be passed by URL because there's no video analogue to UIImage. When I pass a URL to a video, I get an error "Could not create sandbox extension". If I pass a URL to an image, I get a similar error.
Based on this, it seems as though I might be able to get around this error by exporting the assets to the Documents directory, and passing UIActivityViewController the URL to the asset in Documents. However, I've read elsewhere that the Camera Roll can serve a similar purpose, and it goes to reason that the Camera Roll would be one of the few places that can hold data for sharing between apps.
Is there a way to pass UIActivityViewController URLs to Camera Roll assets without copying them to Documents? Is there a better way to be sharing images and video that are already in Camera Roll?
Implementation Details:
I'm generating URLs for assets using this:
func videoFor(asset: PHAsset, resultHander: #escaping (AVAsset?, AVAudioMix?, [AnyHashable : Any]?) -> Void) {
imageManager.requestAVAsset(forVideo: asset, options: nil, resultHandler: resultHander)
}
func urlFor(asset: PHAsset, resultHandler: #escaping (URL?) -> Void) {
if ( asset.mediaType == .video ) {
videoFor(asset: asset) { (asset, audioMix, info) in
let asset = asset as! AVURLAsset
resultHandler(asset.url)
}
}
else if ( asset.mediaType == .image ) {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
asset.requestContentEditingInput(with: options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) -> Void in
resultHandler(contentEditingInput!.fullSizeImageURL as URL?)
})
}
else {
resultHandler(nil)
}
}
Here is the full error I get in console when trying to share an image by URL:
Failed to determine whether URL /var/mobile/Media/DCIM/100APPLE/IMG_0201.JPG (n) is managed by a file provider
Could not create sandbox extension. Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Could not create sandbox extension of type com.apple.app-sandbox.read for URL /var/mobile/Media/DCIM/100APPLE/IMG_0201.JPG. Error: No such file or directory}
... and for a video:
Failed to determine whether URL /var/mobile/Media/DCIM/100APPLE/IMG_0202.M4V (n) is managed by a file provider
Could not create sandbox extension. Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Could not create sandbox extension of type com.apple.app-sandbox.read for URL /var/mobile/Media/DCIM/100APPLE/IMG_0202.M4V. Error: Operation not permitted}
I was stuck on the same problem today. Here is my solution. Hope this helps or guides you to the right path.
PHImageManager.default().requestExportSession(forVideo: video, options: nil, exportPreset: AVAssetExportPresetPassthrough) { (exportSession, nil) in
if let exportSession = exportSession {
exportSession.outputURL = destinationURLForFile
exportSession.outputFileType = AVFileType.m4v
exportSession.exportAsynchronously() {
// Load the share sheet using destinationURLForFile
}
}
}
What this does is export the video to the provided location destinationURLForFile (i used the Documents directory. Make sure you delete the file if its already there otherwise the export MAY not work cause it may not override the file).
You can set the type based on available types. I needed m4v.
Then, export async and just call the share sheet or whatever sharing mechanism you have.
I am picking image using UIImagePickerController but I also need image’s name and other metadata information. I could have fetched image asset using ALAsssetsLibrary’s assetForURL:resultBlock:failure method with the help of referenceURL provided by UIImagePickerController after picking image but that method/Framework is deprecated in iOS9. I searched for its equivalent method in Photos Framework but I didn’t find one.
Let me know its equivalent method or any other way to fetch selected image’s metadata using Photos Framework.
Yes you can read metada with Photos Framework like that;
asset.requestContentEditingInputWithOptions(options) { (fooContentEditingInput: PHContentEditingInput!, _) -> Void in
//Get full image
let imageUrl = fooContentEditingInput.fullSizeImageURL
let orientation = fooContentEditingInput.fullSizeImageOrientation
var finalImage = CIImage(contentsOfURL: imageUrl)
finalImage = inputImage.imageByApplyingOrientation(orientation)
for (key, value) in finalImage.properties() {
println("key: \(key)")
println("value: \(value)")
}
}
Is there a way to know the ALAsset corresponding to an UIImage?
I use UIImageWriteToSavedPhotosAlbum for saving a photo and I need to identify it in my asset list
UPDATE :
I used writeImageToSavedPhotosAlbum instead of UIImageWriteToSavedPhotosAlbum
alAssetLibrary.writeImageToSavedPhotosAlbum(image.CGImage, orientation: orientation) { (url, error) -> Void in
alAssetLibrary.assetForURL(url, resultBlock: { (asset) -> Void in
//code
}, failureBlock: { (error) -> Void in
//code
})
}
I use UIImageWriteToSavedPhotosAlbum for saving a photo and I need to identify it in my asset list
If you need to identify the resulting asset, why are you using UIImageWriteToSavedPhotosAlbum? It is a "stupid" function.
If you want to save an image as an asset into the library in such a way that you have access to that asset, you need to save it a "smart" way, such ALAssetsLibrary's writeImageToSavedPhotosAlbum - which has a completion handler that hands you the URL of the resulting asset.
i want to get some extra info about the images i'll share with the Share extension. I can create the UIImage from the url but when i want to obtain an ALAsset i get nil. Anyone had this problem?
itemProvider!.loadItemForTypeIdentifier(String(kUTTypeImage), options: nil, completionHandler: { (decoder: NSSecureCoding!, error: NSError!) -> Void in
if ALAssetsLibrary.authorizationStatus() == ALAuthorizationStatus.Authorized {
if let url = decoder as? NSURL {
ALAssetsLibrary().assetForURL(url, resultBlock: { (myasset:ALAsset!) -> Void in
println(url)
println(fm.fileExistsAtPath(url.path!))
println(myasset)
let location = myasset?.valueForProperty(ALAssetPropertyLocation) as CLLocation?
let date = myasset?.valueForProperty(ALAssetPropertyDate) as NSDate?
self.extensionContext?.completeRequestReturningItems([AnyObject](), completionHandler: nil)
}, failureBlock: { (myerror:NSError!) -> Void in
})
}
}
The output is
file:///var/mobile/Media/DCIM/102APPLE/IMG_2977.JPG
true
nil
the immediate issue is you are passing a file url in place of an asset url for this line: ALAssetsLibrary().assetForURL(url, resultBlock: { (myasset:ALAsset!) -> Void in.
Share extensions return the url to the path on the iphone's file system...something of the form: file:///..... These are not the same as the urls that an ALAsset require in the assetForURL method.
Unfortunately, though this makes the code more correct, it still doesn't fix the issue. I spent some time with many different approaches. Writing a new image to disk via the AssetsLibrary and the given file path will return an asset url upon completion which will work successfully - though you obviously don't want duplicate photos in your camera roll. (Note: there is no way to delete an ALAsset). You could probably hold onto the file path and delete the new image when you are done with it, but that is an extremely messy approach.
I ended up rewriting my approach given these limitations.
I have code for fetching the photos from the library and accessing the types. But i have no idea how to check whether the image is PNG or JPEG.? by ALAssetLibrary we can do this easily. I want to implement this by Photos framework. Anyone have any idea.? Any suggestions. Thanks in advance.
Try:
let asset: PHAsset = ...
let opts = PHImageRequestOptions()
// opts.synchronous = true // If you want synchronous callback
opts.version = PHImageRequestOptionsVersion.Original
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: opts) { _, uti, _, _ in
println(uti)
}
I don't know how to do this without fetching actual data.
To convert UTI to MIME-Type:
import MobileCoreServices
let uti = ...
let mime = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType).takeRetainedValue()
Please refer this stack answer using which you can get type of you asset.
https://stackoverflow.com/a/22352132/2098690