A beautiful, simple, declarative, convenient, cross-platform (iOS, macOS & tvOS) and unit-tested wrapper API for Apple's PhotoKit
What I don't like about PhotoKit
is that it's not declarative and that developers have to think about too many details.
That's why I created this Swift package which will dramatically improve the readability of your PhotoKit
code.
Easily fetch media from the photo library with Albums.all
, album.photos
or Photos.live
and many more.
Additionally you can perform many operations on the photo library in a very easy and robust way, like
Check out the below API section for more.
And please feel free to contribute. Any kind of contribution is more than welcome! I can guarantee you that even with a good unit test coverage there are still bugs hiding somewhere đ.
Just add this Swift package as a dependency to your Package.swift
.package(url: "https://github.com/crelies/Media.git", from: "0.1.0"),
This Swift package provides its functionality through wrapper types for many common PhotoKit
media types:
Many types implement static factory methods to make it easy for the developer to access and manage the photo library.
In addition to that this Swift package contains some simple and ready-to-use SwiftUI views for interacting with the photo library, like a Camera
view or a view for an instance of LivePhoto
, Photo
and Video
.
The core functionality is available through import MediaCore
. If you want to use the included SwiftUI views import MediaSwiftUI
as well.
That's all you need to know. Now let's take a look at the API.
Check out the example project in the Example
directory to explore the power of this Swift package.
This section gives you an overview of the currently available functionality. Most of the following should be self-explanatory. Nevertheless every public type, function and property is documented. If the Xcode autocompletion works you should get the information you need when using the APIs provided by this Swift package đ.
Media.requestPermission { result in }
Request the users permission to access his photo library
Media.requestCameraPermission { result in }
Requests the user's permission to access the camera
Media.isAccessAllowed
Check if the access to the photo library is allowed
Media.currentPermission
Get the current permission
Media.currentCameraPermission
Get the current camera permission
SwiftUI only: Media.browser(selectionLimit:) { result in }
(some View)
Creates a ready-to-use media browser SwiftUI view (UIImagePickerController) for photos and videos
Use the LazyAlbums
wrapper if you want to fetch albums only on demand (request an album through the provided subscript
on the LazyAlbums
type).
Albums.all
Fetch all albums in the photo library
Albums.user
Fetch all albums related to the user
Albums.smart
Fetch all smart albums, like screenshots, self-portraits, ...
Albums.cloud
Fetch all cloud albums, like the photo stream or the iCloud shared album
album.metadata
Get locally available metadata of the album, like the estimated asset count or the earliest creation date among all assets in the album
album.audios
Get all audios in the album
album.livePhotos
Access all live photos in album
album.photos
Fetch all photos in the album
album.videos
Fetch all videos in the album
album.allMedia
Get all media items in the album (audios, (live) photos and videos)
Album.create(title:) { result in }
Create an album with the given title
Album.with(identifier:) -> Album?
Get an album with the given identifier
Album.with(localizedTitle:) -> Album?
Get an album with the given localized title
album.add(audio|livePhoto|photo|video) { result in }
Add the given media item (audio, (live) photo or video) to the album
album.delete(audio|livePhoto|photo|video) { result in }
Deletes the given media item (audio, (live) photo or video) from the album
album.delete { result in }
Deletes the album
Use the LazyAudios
wrapper if you want to fetch audios only on demand (request an audio through the provided subscript
on the LazyAudios
type).
Audios.all
Get all audios in the photo library
Audio.with(identifier:) - > Audio? (check for existence if you want)
Get an audio with the given identifier
audio.metadata
Fetch the locally available metadata of the audio
audio.delete { result in }
Deletes the audio
SwiftUI only: Camera.view { result in }
(some View)
Creates a ready-to-use camera SwiftUI view (UIImagePickerController) for capturing photos and videos
Use the LazyLivePhotos
wrapper if you want to fetch live photos only on demand (request a live photo through the provided subscript
on the LazyLivePhotos
type).
LivePhotos.all
Get all live photos in the photo library
livePhoto.metadata
Fetch the locally available metadata of the live photo
livePhoto.displayRepresentation(targetSize:contentMode) { result in }
Get a PHLivePhoto representation of the live photo
LivePhoto.save(data:) { result in }
Create a new live photo in the library from the given data object (LivePhotoData: holds image and video portion)
LivePhoto.with(identifier:) -> LivePhoto? (check for existence if you want)
Get a live photo with the given identifier
livePhoto.delete { result in }
Delete the receiving live photo
livePhoto.favorite(true|false) { result in }
Update the favorite state of the receiving live photo
SwiftUI only: LivePhoto.camera { result in }
(some View)
Creates a ready-to-use SwiftUI camera view for capturing live photos (this is not a UIImagePickerController)
SwiftUI only: LivePhoto.browser(selectionLimit:) { result in }
(some View)
Creates a ready-to-use SwiftUI view for browsing live photos in the library (UIImagePickerController)
SwiftUI only: livePhoto.view(size:)
(some View)
Get a ready-to-use SwiftUI view for displaying the receiving live photo in your UI
Use the Media.LazyPhotos
wrapper if you want to fetch photos only on demand (request a photo through the provided subscript
on the Media.LazyPhotos
type).
Media.Photos.all (includes livePhotos)
Get all photos in the library, including the live photos
Media.Photos.live
Get all live photos in the library
Media.Photos.panorama
Fetch all panorama photos in the library
Media.Photos.hdr
Get all HDR photos
Media.Photos.screenshot
Get all screenshots in the library
Media.Photos.depthEffect
Fetch all depth effect photos in the library
photo.metadata
Fetch all locally available metdata of the photo
photo.subtypes
Get all subtypes of the photo, like HDR or panorama
photo.properties { result in }
Fetch all properties (metadata) of the photo, including EXIF, GPS and TIFF data
photo.data { result in }
Get a data representation of the photo
photo.uiImage(targetSize:contentMode:) { result in }
Get a UIImage representation of the photo
Photo.save(Media.URL<Photo>) { result in }
Create a new photo using the given photo url
Photo.save(UIImage) { result in }
Create a new photo from the given UIImage instance
Photo.with(identifier:) -> Photo?
Get a photo with the given identifier
photo.delete { result in }
Delete the receiving photo
photo.favorite(true|false) { result in }
Update the favorite state of the receiving photo
SwiftUI only: Photo.camera { result in }
(some View)
Creates a ready-to-use camera SwiftUI view for capturing photos (UIImagePickerController)
SwiftUI only: Photo.browser(selectionLimit:) { result in }
(some View)
Creates a ready-to-use SwiftUI view for browsing photos in the library (UIImagePickerController)
SwiftUI only: photo.view(targetSize:contentMode:) { image in image.resizable().aspectRatio(contentMode: .fit) }
(some View)
Get a ready-to-use SwiftUI view for displaying the photo in your UI
Use the LazyVideos
wrapper if you want to fetch videos only on demand (request a video through the provided subscript
on the LazyVideos
type).
Videos.all
Get all videos in the library
Videos.streams
Get all video streams in the library
Videos.highFrameRates
Fetch all high frame rates videos in the library
Videos.timelapses
Get all timelapse videos in the library
video.subtypes
Get the subtypes of the receiving video, like high frame rate
video.metadata
Fetch all locally available metadata
video.properties { result in }
Get all properties (metadata) of the video, including location and model data
video.playerItem(deliveryMode:) { result in }
Get an AVPlayerItem representation of the receiving video
video.avAsset(deliveryMode:) { result in }
Fetch an AVAsset representation of the video
video.previewImage(at:) { result in }
Generates a preview image for the receiving video
video.export(options, progress: { progress in }) { result in }
Export the receiving video using the given options
Video.save(Media.URL<Video>) { result in }
Create a new video using the given url
Video.with(identifier:) -> Video?
Get a video with the given identifier
video.favorite(true|false) { result in }
Update the favorite state of the receiving video
video.delete { result in }
Delete the video
SwiftUI only: Video.camera { result in }
(some View)
Creates a ready-to-use video camera SwiftUI view for capturing videos (UIImagePickerController)
SwiftUI only: Video.browser(selectionLimit:) { result in }
(some View)
Creates a ready-to-use SwiftUI view for browsing videos in the library
SwiftUI only: video.view
(some View)
Get a ready-to-use SwiftUI view for displaying the video in your UI
PHPicker: SwiftUI port of the PHPickerViewController
Use the PHPickerViewController
in your SwiftUI
applications
PhotosUILivePhotoView: SwiftUI port of the PHLivePhotoView
Use the PHLivePhotoView
in your SwiftUI
applications
@propertyWrapper
The Media
package also includes some generic property wrappers you can use to interact with the photo library.
@FetchAllAssets(sort:fetchLimit:includeAllBurstAssets:includeHiddenAssets) var assets: [AnyMedia]
@FetchAssets(filter:sort:fetchLimit:includeAllBurstAssets:includeHiddenAssets) var assets: [ <Audio | LivePhoto | Photo | Video> ]
Fetch audios, live photos, photos or videos matching the given filter and sorted by the given sort
@FetchAsset(filter:) var asset: <Audio | LivePhoto | Photo | Video>?
Fetch a single audio, live photo, photo or video from the library which matches the given filter
@FetchAlbums(ofType:filter:sort:fetchLimit) var albums: [Album]
Fetch albums of the given type which match the given filter, matching albums are sorted by the given sort
@FetchAlbum(filter:) var album: Album?
Fetch a single album which matches the given filter
This a another open source project I created in my free time. Even with a full time job and a family I'm highly motivated to create software for the community. I trust the community in pushing things forward. So feel free to contribute in any way. Fix bugs, add more documentation or add a completely new feature. Just create a pull request if you are finished and I will take a look at it. Be advised that I will give feedback to assure the highest quality possible đ
link |
Stars: 115 |
Last commit: 1 week ago |
New additional lazy containers for fetching the media assets only on demand
-- LazyAlbum(s)
-- LazyAudio(s)
-- LazyLivePhoto(s)
-- Media.LazyPhotos
-- LazyPhoto
-- LazyVideo(s)
Media: Get and request the permission to access the camera (Media.currentCameraPermission
, Media.requestCameraPermission(_)
)
Video: Get a preview image for a given point in time (video.previewImage(at:preferredTimescale:_)
)
Photo+SwiftUI: Get a photo view with a desired size (photo.view(targetSize:imageView:)
)
Refactored views for better performance and to get rid of some bugs
Media.browser
, LivePhoto.browser
, Photo.browser
& Video.browser
now use the new PHPicker
with multi selection support under the hood on iOS 14 or macOS 11
Camera.view
, Media.browser
, LivePhoto.camera
, LivePhoto.browser
, Photo.camera
, Photo.browser
, Video.camera
& Video.browser
stop throwing and instead show a SwiftUI.Text
if an error occurs during initialization. You can specify a ViewBuilder to show a custom error view.
Album
, Audio
, LivePhoto
, Photo
& Video
now conform to Equatable
and Hashable
Fixed a threading issue
Improvements related to the authorization status API changes from Apple
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics