Which Phassetcollection to Use for Saving an Image

Which PHAssetCollection to use for saving an image?

You don't need to mess around with PHAssetCollection. Just add by doing:

    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:<#your photo here#>];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
<#your completion code here#>
}
else {
<#figure out what went wrong#>
}
}];

Save UIImage to PHAssetCollection

In general you're doing things in the wrong order; you should not be doing any fetching inside a performChanges block. And you don't have to, in any case. Do not fetch the collection at all. Just create the photo, plain and simple, exactly as in your first line - except that you don't even need to keep a reference to the change request:

[PHAssetChangeRequest creationRequestForAssetFromImage:image];

...and stop. At that point the photo has been added to the camera roll.

I just tried this and it works perfectly.

(Of course I'm assuming you have already obtained the necessary permissions from the user...!)

Get Specific Photo from Specific Photo Album with PHAssetCollection in Swift 4

You can use this class .

import Foundation
import Photos

class FetchPhotos{

var images:[UIImage] = []
var imageUrl:String!

func fetchPhotos() -> String{
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: false)]

// Fetch the image assets
let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)

// If the fetch result isn't empty,
// proceed with the image request
if fetchResult.count > 0 {
let totalImageCountNeeded = 1 // <-- The number of images to fetch
fetchPhotoAtIndex(0, totalImageCountNeeded, fetchResult)
}
return imageUrl
}

// Repeatedly call the following method while incrementing
// the index until all the photos are fetched
func fetchPhotoAtIndex(_ index:Int, _ totalImageCountNeeded: Int, _ fetchResult: PHFetchResult<PHAsset>) {

let albumName = "CustonAlbum"
// Note that if the request is not set to synchronous
// the requestImageForAsset will return both the image
// and thumbnail; by setting synchronous to true it
// will return just the thumbnail
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true

let collection: PHFetchResult =
PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: nil)
for k in 0 ..< collection.count {
let obj:AnyObject! = collection.object(at: k)
if obj.title == albumName {
print("Yeap!")

// Perform the image request
PHImageManager.default().requestImage(for: fetchResult.object(at: index) as PHAsset, targetSize: CGSize(width: 1000, height: 1000), contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: { (image, info) in

if let image = image {
// Add the returned image to your array
self.images += [image]
}
// If you haven't already reached the first
// index of the fetch result and if you haven't
// already stored all of the images you need,
// perform the fetch request again with an
// incremented index
if index + 1 < fetchResult.count && self.images.count < totalImageCountNeeded {
self.fetchPhotoAtIndex(index + 1, totalImageCountNeeded, fetchResult)
} else {
// Else you have completed creating your array
print("Completed array: \(self.images[0])")
print("Image URL \(String(describing: info!["PHImageFileURLKey"]))")
self.imageUrl = "\(info!["PHImageFileURLKey"]!)"
}
})

}}
}

}

Save images with phimagemanager to custom album?

This is how I do:

At the top:

import Photos

var image: UIImage!
var assetCollection: PHAssetCollection!
var albumFound : Bool = false
var photosAsset: PHFetchResult!
var assetThumbnailSize:CGSize!
var collection: PHAssetCollection!
var assetCollectionPlaceholder: PHObjectPlaceholder!

Creating the album:

func createAlbum() {
//Get PHFetch Options
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", "camcam")
let collection : PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
//Check return value - If found, then get the first album out
if let _: AnyObject = collection.firstObject {
self.albumFound = true
assetCollection = collection.firstObject as! PHAssetCollection
} else {
//If not found - Then create a new album
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle("camcam")
self.assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
}, completionHandler: { success, error in
self.albumFound = success

if (success) {
let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([self.assetCollectionPlaceholder.localIdentifier], options: nil)
print(collectionFetchResult)
self.assetCollection = collectionFetchResult.firstObject as! PHAssetCollection
}
})
}
}

When saving the photo:

func saveImage(){
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(self.image)
let assetPlaceholder = assetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
albumChangeRequest!.addAssets([assetPlaceholder!])
}, completionHandler: { success, error in
print("added image to album")
print(error)

self.showImages()
})
}

Showing the images from that album:

func showImages() {
//This will fetch all the assets in the collection

let assets : PHFetchResult = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: nil)
print(assets)

let imageManager = PHCachingImageManager()
//Enumerating objects to get a chached image - This is to save loading time
assets.enumerateObjectsUsingBlock{(object: AnyObject!,
count: Int,
stop: UnsafeMutablePointer<ObjCBool>) in

if object is PHAsset {
let asset = object as! PHAsset
print(asset)

let imageSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)

let options = PHImageRequestOptions()
options.deliveryMode = .FastFormat

imageManager.requestImageForAsset(asset, targetSize: imageSize, contentMode: .AspectFill, options: options, resultHandler: {(image: UIImage?,
info: [NSObject : AnyObject]?) in
print(info)
print(image)
})
}
}

How to save image to custom album?

I came up with this singleton class to handle it:

import Photos

class CustomPhotoAlbum {

static let albumName = "Flashpod"
static let sharedInstance = CustomPhotoAlbum()

var assetCollection: PHAssetCollection!

init() {

func fetchAssetCollectionForAlbum() -> PHAssetCollection! {

let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)

if let firstObject: AnyObject = collection.firstObject {
return collection.firstObject as! PHAssetCollection
}

return nil
}

if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}

PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(CustomPhotoAlbum.albumName)
}) { success, _ in
if success {
self.assetCollection = fetchAssetCollectionForAlbum()
}
}
}

func saveImage(image: UIImage) {

if assetCollection == nil {
return // If there was an error upstream, skip the save.
}

PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
albumChangeRequest.addAssets([assetPlaceholder])
}, completionHandler: nil)
}

}

When you first instantiate the class, the custom album will be created if it doesn't already exist. You can save an image like this:

CustomPhotoAlbum.sharedInstance.saveImage(image)

NOTE: The CustomPhotoAlbum class assumes the app already has permission to access the Photo Library. Dealing with the permissions is a bit outside the scope of this question/answer. So make sure PHPhotoLibrary.authorizationStatus() == .Authorize before you use it. And request authorization if necessary.

Choosing a picture causes resave to camera roll

I posted a similar question:
Swift 3 or 4 Saving to custom album creates duplicate images

But I got nothing but crickets as well. Luckily, I think I found the answer. I'll answer my own question as well.

The code you have (which was the same code I had) is to CREATE A NEW ASSET. It is useful only for the saving the image to your custom album after the user has taken a picture with the camera. It is for brand new assets.

However, for existing assets, you do not want to create a new asset. Instead, you want to add the existing asset to the custom album. To do this, you need a different method. Here is the code I created and it seems to be working. Keep in mind that you will have to get the asset ID FIRST, so that you can send it to your method and access the existing asset.

So, in your imagePickerController, you have to determine whether the user chose an existing image or whether the method is being called from a new camera action.

let pickerSource = picker.sourceType;
switch(pickerSource){
case .savedPhotosAlbum, .photoLibrary:
if(let url = info[UIIMagePickerControllerReferenceURL] as? NSURL{
let refURLString = refURL?.absoluteString;
/* value for refURLString looks something like assets-library://asset/asset.JPG?id=82A6E75C-EA55-4C3A-A988-4BF8C7F3F8F5&ext=JPG */
let refID = {function here to extract the id query param from the url string}
/*above gets you the asset ID, you can get the asset directly, but it is only
available in ios 11+.
*/
MYPHOTOHELPERCLASS.transferImage(toAlbum: "myalbumname", withID: refID!, ...)

}
break;
case .camera:
...
break;
}

Now, in your photohelper class (or in any function anywhere, whatever), to EDIT the asset instead of create a new one, this is what I have. I am assuming the changeRequest variable can be ommitted. I was just playing around until I got this right. Going through the completely ridiculous apple docs I was able to at least notice that there were other methods to play with. I found that the NSFastEnumeration parameter can be an NSArray of PHAssets, and not just placeholder PHObjectPlaceholder objects.

public static func transferImage(toAlbum albumName:String, withID imageID:String, onSuccess success:@escaping(String)->Void, onFailure failure:@escaping(Error?)->Void){

guard let album = self.getAlbum(withName: albumName) else{
... failure here, albumNotFoundError
return;
}

if(self.hasImageInAlbum(withIdentifier: imageID, fromAlbum: albunName)){
... failure here, image already exists in the album, do not make another
return;
}

let theAsset = self.getExistingAsset(withLocalIdentifier: imageID);
if(theAsset == nil){
... failure, no asset for asset id
return;
}

PHPhotoLibrary.shared().performChanges({
let albumChangeRequest = PHAssetCollectionChangeRequest(for: album);
let changeRequest = PHAssetChangeRequest.init(for: theAsset!);
let enumeration:NSArray = [theAsset!];
let cnt = album.estimatedAssetCount;
if(cnt == 0){
albumChangeRequest?.addAssets(enumeration);
}else{
albumChangeRequest?.inserAssets(enumeration, at: [0]);
}
}){didSucceed, error) in
OperationQueue.main.addOperation({
didSucceed ? success(imageID) : failure(error);
})
}

}

So, it is pretty much the same, except instead of creating an Asset Creation Request and generating a placeholder for the created asset, you instead just use the existing asset ID to fetch an existing asset and add the existing asset to the addasset/insertasset NSArray parameter instead of a newly created asset placeholder.

Unable to Save UIImage to Camera Roll in Swift 5 XCode 11.6

I have figured it out.

The problem is I have been creating QR Image that is created with CIFilter is CIImage.

It returns error code = -1

You need to create UIImage from CGImage not CIImage

if let output = filter.outputImage?.transformed(by: transform) {
let context = CIContext()
guard let cgImage = context.createCGImage(output, from: output.extent) else { return nil }
return UIImage(cgImage: cgImage)

}



Related Topics



Leave a reply



Submit