Skip to content

Instantly share code, notes, and snippets.

@lacyrhoades
Last active September 26, 2022 14:07
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lacyrhoades/ccf185739d46ca8743ffd4b7df04602d to your computer and use it in GitHub Desktop.
Save lacyrhoades/ccf185739d46ca8743ffd4b7df04602d to your computer and use it in GitHub Desktop.
import Foundation
import Photos
typealias AssetID = String
class ImageUtil {
static var defaultAlbumName = "App Name"
static var videosAlbumName = "App Name Videos"
static func saveFileToCameraRoll(fromPath: String) {
var albumName = ImageUtil.defaultAlbumName
var isVideo: Bool = false
if fromPath.localizedStandardContains("mp4") {
albumName = ImageUtil.videosAlbumName
isVideo = true
}
let fromURL = URL(fileURLWithPath: fromPath)
guard let album = ImageUtil.findOrCreateAlbum(named: albumName) else {
assert(false, "Could not find or create album")
return;
}
DispatchQueue.global().async {
PHPhotoLibrary.shared().performChanges({
var assetReq: PHAssetChangeRequest?
if isVideo {
assetReq = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: fromURL)
} else {
assetReq = PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: fromURL)
}
if let asset = assetReq?.placeholderForCreatedAsset {
let request = PHAssetCollectionChangeRequest(for: album)
request?.addAssets([asset] as NSArray)
}
}) { (done, err) in
if err != nil {
print("Error creating video file in library")
print(err.debugDescription)
} else {
print("Done writing asset to the user's photo library")
}
}
}
}
static func save(_ image: UIImage, toAlbumNamed albumName: String, andThen: @escaping (AssetID?) -> ()) {
DispatchQueue.global().async {
if let album = ImageUtil.findOrCreateAlbum(named: albumName) {
var localIdentifier: AssetID? = nil
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let asset = assetChangeRequest.placeholderForCreatedAsset
localIdentifier = asset?.localIdentifier
let request = PHAssetCollectionChangeRequest(for: album)
request?.addAssets([asset!] as NSArray)
}, completionHandler: { (success, error) in
if success {
andThen(localIdentifier)
}
})
}
}
}
static func saveVideo(atURL url: URL, toAlbumNamed albumName: String, andThen: @escaping (AssetID?) -> ()) {
guard FileUtil.fileExists(url.path) else {
assert(false, "File does not exist and cannot be saved to Camera Roll")
return
}
DispatchQueue.global().async {
if let album = ImageUtil.findOrCreateAlbum(named: albumName) {
var localIdentifier: AssetID? = nil
PHPhotoLibrary.shared().performChanges({
if let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url) {
let asset = assetChangeRequest.placeholderForCreatedAsset
localIdentifier = asset?.localIdentifier
let request = PHAssetCollectionChangeRequest(for: album)
request?.addAssets([asset!] as NSArray)
} else {
print("Creation request for video failed")
}
}, completionHandler: { (success, error) in
if success {
andThen(localIdentifier)
} else {
print("Creation request failed")
print(error?.localizedDescription ?? "None")
}
})
}
}
}
static func findOrCreateAlbum(named albumName: String) -> PHAssetCollection? {
if let album = ImageUtil.findAlbum(named: albumName) {
return album
} else {
do {
try PHPhotoLibrary.shared().performChangesAndWait({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName)
})
} catch {
print("Problem finding/creating album: ".appending(albumName))
print(error)
}
return ImageUtil.findAlbum(named: albumName)
}
}
static func findAlbum(named albumName: String) -> PHAssetCollection? {
let options = PHFetchOptions()
options.predicate = NSPredicate(format: "title = %@", albumName)
let findAlbumResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: options)
return findAlbumResult.firstObject
}
static func clearCameraRoll() {
let options = PHFetchOptions()
let fetch: PHFetchResult<PHAsset> = PHAsset.fetchAssets(with: options)
var assets: [PHAsset] = []
fetch.enumerateObjects({ (asset, index, test) in
assets.append(asset)
})
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.deleteAssets(assets as NSArray)
}) { (result, error) in
// done
}
}
static func assetExists(_ assetID: AssetID) -> Bool {
let options = PHFetchOptions()
let request = PHAsset.fetchAssets(withLocalIdentifiers: [assetID], options: options)
return request.count > 0
}
}
@Proudspark
Copy link

Hi there,

this looks like a very thorough toolkit for dealing with image assets. 8•) - as a newbie to Swift - I'm wondering how to use it. I'm trying to save a replaykit video to a custom Photos Album, using ImageUtil.saveVideo method, but I think I need to set everything else up first. Have you got a demo of how to use this class? Many many thanks!

@animis93
Copy link

animis93 commented Jul 10, 2018

Hi there,
i have to save a video from Bundle.main and then share the video on Facebook. I don't know how to retreive url of the video saved in library without pickerController.

ps. sorry for my english :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment