123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- //
- // DKAsset.swift
- // DKImagePickerControllerDemo
- //
- // Created by ZhangAo on 15/12/13.
- // Copyright © 2015年 ZhangAo. All rights reserved.
- //
- import Photos
- public extension CGSize {
-
- public func toPixel() -> CGSize {
- let scale = UIScreen.main.scale
- return CGSize(width: self.width * scale, height: self.height * scale)
- }
- }
- /**
- An `DKAsset` object represents a photo or a video managed by the `DKImagePickerController`.
- */
- open class DKAsset: NSObject {
- /// Returns a UIImage that is appropriate for displaying full screen.
- private var fullScreenImage: (image: UIImage?, info: [AnyHashable: Any]?)?
-
- /// When the asset was an image, it's false. Otherwise true.
- @objc open private(set) var isVideo: Bool = false
-
- /// Returns location, if its contained in original asser
- open private(set) var location: CLLocation?
-
- /// play time duration(seconds) of a video.
- open private(set) var duration: Double?
-
- @objc open private(set) var originalAsset: PHAsset?
-
- open var localIdentifier: String
-
- public init(originalAsset: PHAsset) {
- self.localIdentifier = originalAsset.localIdentifier
- self.location = originalAsset.location
- super.init()
-
- self.originalAsset = originalAsset
-
- let assetType = originalAsset.mediaType
- if assetType == .video {
- self.isVideo = true
- self.duration = originalAsset.duration
- }
- }
-
- private var image: UIImage?
- internal init(image: UIImage) {
- self.localIdentifier = String(image.hash)
- super.init()
-
- self.image = image
- self.fullScreenImage = (image, nil)
- }
-
- override open func isEqual(_ object: Any?) -> Bool {
- if let another = object as? DKAsset {
- return self.localIdentifier == another.localIdentifier
- }
- return false
- }
-
- public func fetchImageWithSize(_ size: CGSize, completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- self.fetchImageWithSize(size, options: nil, completeBlock: completeBlock)
- }
-
- public func fetchImageWithSize(_ size: CGSize, options: PHImageRequestOptions?, completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- self.fetchImageWithSize(size, options: options, contentMode: .aspectFit, completeBlock: completeBlock)
- }
-
- public func fetchImageWithSize(_ size: CGSize, options: PHImageRequestOptions?, contentMode: PHImageContentMode, completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- if let _ = self.originalAsset {
- getImageManager().fetchImageForAsset(self, size: size, options: options, contentMode: contentMode, completeBlock: completeBlock)
- } else {
- completeBlock(self.image, nil)
- }
- }
-
- public func fetchFullScreenImageWithCompleteBlock(_ completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- self.fetchFullScreenImage(false, completeBlock: completeBlock)
- }
-
- /**
- Fetch an image with the current screen size.
-
- - parameter sync: If true, the method blocks the calling thread until image is ready or an error occurs.
- - parameter completeBlock: The block is executed when the image download is complete.
- */
- public func fetchFullScreenImage(_ sync: Bool, completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- if let (image, info) = self.fullScreenImage {
- completeBlock(image, info)
- } else {
- let screenSize = UIScreen.main.bounds.size
-
- let options = PHImageRequestOptions()
- options.deliveryMode = .highQualityFormat
- options.resizeMode = .exact
- options.isSynchronous = sync
- getImageManager().fetchImageForAsset(self, size: screenSize.toPixel(), options: options, contentMode: .aspectFit) { [weak self] image, info in
- guard let strongSelf = self else { return }
-
- strongSelf.fullScreenImage = (image, info)
- completeBlock(image, info)
- }
- }
- }
-
- public func fetchOriginalImageWithCompleteBlock(_ completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- self.fetchOriginalImage(false, completeBlock: completeBlock)
- }
-
- /**
- Fetch an image with the original size.
-
- - parameter sync: If true, the method blocks the calling thread until image is ready or an error occurs.
- - parameter completeBlock: The block is executed when the image download is complete.
- */
- public func fetchOriginalImage(_ sync: Bool, completeBlock: @escaping (_ image: UIImage?, _ info: [AnyHashable: Any]?) -> Void) {
- let options = PHImageRequestOptions()
- options.version = .current
- options.isSynchronous = sync
-
- getImageManager().fetchImageDataForAsset(self, options: options, completeBlock: { (data, info) in
- var image: UIImage?
- if let data = data {
- image = UIImage(data: data)
- }
- completeBlock(image, info)
- })
- }
-
- /**
- Fetch an image data with the original size.
-
- - parameter sync: If true, the method blocks the calling thread until image is ready or an error occurs.
- - parameter completeBlock: The block is executed when the image download is complete.
- */
- public func fetchImageDataForAsset(_ sync: Bool, completeBlock: @escaping (_ imageData: Data?, _ info: [AnyHashable: Any]?) -> Void) {
- let options = PHImageRequestOptions()
- options.version = .current
- options.isSynchronous = sync
-
- getImageManager().fetchImageDataForAsset(self, options: options, completeBlock: { (data, info) in
- completeBlock(data, info)
- })
- }
-
- /**
- Fetch an AVAsset with a completeBlock.
- */
- public func fetchAVAssetWithCompleteBlock(_ completeBlock: @escaping (_ AVAsset: AVAsset?, _ info: [AnyHashable: Any]?) -> Void) {
- self.fetchAVAsset(nil, completeBlock: completeBlock)
- }
-
- /**
- Fetch an AVAsset with a completeBlock and PHVideoRequestOptions.
- */
- public func fetchAVAsset(_ options: PHVideoRequestOptions?, completeBlock: @escaping (_ AVAsset: AVAsset?, _ info: [AnyHashable: Any]?) -> Void) {
- getImageManager().fetchAVAsset(self, options: options, completeBlock: completeBlock)
- }
-
- /**
- Sync fetch an AVAsset with a completeBlock and PHVideoRequestOptions.
- */
- public func fetchAVAsset(_ sync: Bool, options: PHVideoRequestOptions?, completeBlock: @escaping (_ AVAsset: AVAsset?, _ info: [AnyHashable: Any]?) -> Void) {
- if sync {
- let semaphore = DispatchSemaphore(value: 0)
- self.fetchAVAsset(options, completeBlock: { (AVAsset, info) -> Void in
- completeBlock(AVAsset, info)
- semaphore.signal()
- })
- _ = semaphore.wait(timeout: DispatchTime.distantFuture)
- } else {
- self.fetchAVAsset(options, completeBlock: completeBlock)
- }
- }
-
- }
- public extension DKAsset {
-
- struct DKAssetWriter {
- static let writeQueue: OperationQueue = {
- let queue = OperationQueue()
- queue.name = "DKAsset_Write_Queue"
- queue.maxConcurrentOperationCount = 5
- return queue
- }()
- }
-
-
- /**
- Writes the image in the receiver to the file specified by a given path.
- */
- public func writeImageToFile(_ path: String, completeBlock: @escaping (_ success: Bool) -> Void) {
- let options = PHImageRequestOptions()
- options.version = .current
-
- getImageManager().fetchImageDataForAsset(self, options: options, completeBlock: { (data, _) in
- DKAssetWriter.writeQueue.addOperation({
- if let imageData = data {
- try? imageData.write(to: URL(fileURLWithPath: path), options: [.atomic])
- completeBlock(true)
- } else {
- completeBlock(false)
- }
- })
- })
- }
-
- /**
- Writes the AV in the receiver to the file specified by a given path.
-
- - parameter presetName: An NSString specifying the name of the preset template for the export. See AVAssetExportPresetXXX.
- */
- public func writeAVToFile(_ path: String, presetName: String, completeBlock: @escaping (_ success: Bool) -> Void) {
- self.fetchAVAsset(nil) { (avAsset, _) in
- DKAssetWriter.writeQueue.addOperation({
- if let avAsset = avAsset,
- let exportSession = AVAssetExportSession(asset: avAsset, presetName: presetName) {
- exportSession.outputFileType = AVFileType.mov
- exportSession.outputURL = URL(fileURLWithPath: path)
- exportSession.shouldOptimizeForNetworkUse = true
- exportSession.exportAsynchronously(completionHandler: {
- completeBlock(exportSession.status == .completed ? true : false)
- })
- } else {
- completeBlock(false)
- }
- })
- }
- }
- }
- public extension AVAsset {
-
- public func calculateFileSize() -> Float {
- if let URLAsset = self as? AVURLAsset {
- var size: AnyObject?
- try! (URLAsset.url as NSURL).getResourceValue(&size, forKey: URLResourceKey.fileSizeKey)
- if let size = size as? NSNumber {
- return size.floatValue
- } else {
- return 0
- }
- } else if let _ = self as? AVComposition {
- var estimatedSize: Float = 0.0
- var duration: Float = 0.0
- for track in self.tracks {
- let rate = track.estimatedDataRate / 8.0
- let seconds = Float(CMTimeGetSeconds(track.timeRange.duration))
- duration += seconds
- estimatedSize += seconds * rate
- }
- return estimatedSize
- } else {
- return 0
- }
- }
-
- }
|