diff --git a/Example/SnapSliderFilters/ViewController.swift b/Example/SnapSliderFilters/ViewController.swift index 15c0bbc..3def4f6 100644 --- a/Example/SnapSliderFilters/ViewController.swift +++ b/Example/SnapSliderFilters/ViewController.swift @@ -8,6 +8,7 @@ import UIKit import SnapSliderFilters +import MobileCoreServices class ViewController: UIViewController { @@ -19,7 +20,7 @@ class ViewController: UIViewController { fileprivate let buttonSave = SNButton(frame: CGRect(x: 20, y: SNUtils.screenSize.height - 35, width: 33, height: 30), withImageNamed: "saveButton") fileprivate let buttonCamera = SNButton(frame: CGRect(x: 75, y: SNUtils.screenSize.height - 42, width: 45, height: 45), withImageNamed: "galleryButton") fileprivate let imagePicker = UIImagePickerController() - fileprivate var data:[SNFilter] = [] + fileprivate var data:[Any] = [] //MARK: Overriden functions override func viewDidLoad() { @@ -90,6 +91,7 @@ class ViewController: UIViewController { if let tmpImagePicker = weakSelf?.imagePicker { tmpImagePicker.allowsEditing = false + tmpImagePicker.mediaTypes = [kUTTypeMovie as String, kUTTypeImage as String ] tmpImagePicker.sourceType = .photoLibrary weakSelf?.present(tmpImagePicker, animated: true, completion: nil) @@ -104,15 +106,49 @@ class ViewController: UIViewController { fileprivate func createData(_ image: UIImage) { self.data = SNFilter.generateFilters(SNFilter(frame: self.slider.frame, withImage: image), filters: SNFilter.filterNameList) - self.data[1].addSticker(SNSticker(frame: CGRect(x: 195, y: 30, width: 90, height: 90), image: UIImage(named: "stick2")!)) - self.data[2].addSticker(SNSticker(frame: CGRect(x: 30, y: 100, width: 250, height: 250), image: UIImage(named: "stick3")!)) - self.data[3].addSticker(SNSticker(frame: CGRect(x: 20, y: 00, width: 140, height: 140), image: UIImage(named: "stick")!)) + let stickers = [ + SNSticker(frame: CGRect(x: 195, y: 30, width: 90, height: 90), image: UIImage(named: "stick2")!), + SNSticker(frame: CGRect(x: 30, y: 100, width: 250, height: 250), image: UIImage(named: "stick3")!), + SNSticker(frame: CGRect(x: 20, y: 00, width: 140, height: 140), image: UIImage(named: "stick")!) + ] + + var i = 0 + while i <= data.count { + if let filter = data[i] as? SNFilter { + filter.addSticker(stickers[i % stickers.count]) + } + i = i + 1 + } + } + + fileprivate func createData(withVideo video: NSURL) { + // Little awkward as the picker gives us an NSURL, but easy to convert to URL. + self.data = SNVideoFilter.generateFilters(SNVideoFilter(frame: self.slider.frame, withVideoAt: video as URL), filters: SNFilter.filterNameList) + + let stickers = [ + SNSticker(frame: CGRect(x: 195, y: 30, width: 90, height: 90), image: UIImage(named: "stick2")!), + SNSticker(frame: CGRect(x: 30, y: 100, width: 250, height: 250), image: UIImage(named: "stick3")!), + SNSticker(frame: CGRect(x: 20, y: 00, width: 140, height: 140), image: UIImage(named: "stick")!) + ] + + var i = 0 + while i <= data.count { + if let filter = data[i] as? SNVideoFilter { + filter.addSticker(stickers[i % stickers.count]) + } + i = i + 1 + } } fileprivate func updatePicture(_ newImage: UIImage) { createData(newImage) slider.reloadData() } + + fileprivate func updateVideo(_ newVideoLocation: NSURL) { + createData(withVideo: newVideoLocation) + slider.reloadData() + } } //MARK: - Extension SNSlider DataSource @@ -124,8 +160,7 @@ extension ViewController: SNSliderDataSource { } func slider(_ slider: SNSlider, slideAtIndex index: Int) -> SNFilter { - - return data[index] + return data[index] as! SNFilter } func startAtIndex(_ slider: SNSlider) -> Int { @@ -147,6 +182,11 @@ extension ViewController: UIGestureRecognizerDelegate { extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { + if let movieURL = info[UIImagePickerControllerMediaURL] as? NSURL { + + // The user has selected a video + updateVideo(movieURL) + } if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage { @@ -156,6 +196,7 @@ extension ViewController: UIImagePickerControllerDelegate, UINavigationControlle updatePicture(image) } } + dismiss(animated: true, completion: nil) } diff --git a/SnapSliderFilters/Classes/SNVideoFilter.swift b/SnapSliderFilters/Classes/SNVideoFilter.swift new file mode 100644 index 0000000..d30f682 --- /dev/null +++ b/SnapSliderFilters/Classes/SNVideoFilter.swift @@ -0,0 +1,119 @@ +// +// SNVideoFilter.swift +// Pods-SnapSliderFilters_Example +// +// Created by Josh Guffey on 8/29/18. +// + +import UIKit +import AVKit + +open class SNVideoFilter: UIView { + var videoLocation: URL? + var currentVideoPlayer: AVPlayer? + var videoPlayerObserver: NSObjectProtocol? + var stickers = [SNSticker]() + open var filterName: String? + + /* + Todo: + - Create Masking methods + - Fill out applyFilter method + - Create addSticker method + - Apply Stickers + - Test in app. + - Update SNSliderDataSource's slider sliderAtIndex method to accept videos. + */ + + public override init(frame: CGRect) { + super.init(frame: frame) + } + + public init(frame: CGRect, withVideoAt url:URL, withContentMode mode:UIViewContentMode = .scaleAspectFill) { + super.init(frame: frame) + self.videoLocation = url + self.contentMode = mode + self.clipsToBounds = true + let maskLayer = CAShapeLayer() + self.layer.mask = maskLayer + maskLayer.frame = frame + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open static func generateFilters(_ originalVideo: SNVideoFilter, filters:[String]) -> [SNVideoFilter] { + var finalFilters = [SNVideoFilter]() + + for filter in filters { + let filterComputed = originalVideo.applyFilter(filterNamed: filter) + finalFilters.append(filterComputed) + } + + return finalFilters + } + + open func addSticker(_ sticker: SNSticker) { + self.stickers.append(sticker) + } + + // MARK: - Video Specific + func setupNonSliderView() { + // Load in the video, and add a sublayer to play the video. + if let url = self.videoLocation { + let player = AVPlayer(url: url) + let playerLayer = AVPlayerLayer(player: player) + playerLayer.backgroundColor = UIColor.clear.cgColor + playerLayer.frame = self.bounds + playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill + self.layer.sublayers? + .filter { $0 is AVPlayerLayer } + .forEach { $0.removeFromSuperlayer() } + self.layer.addSublayer(playerLayer) + + // Configure the player. + player.play() + player.allowsExternalPlayback = false + + // Configure the video to loop. + self.videoPlayerObserver = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { (_) in + player.seek(to: kCMTimeZero) + player.play() + } + + // Store player for later use + self.currentVideoPlayer = player + } + } + + // MARK: - Video Filtering + func applyFilter(filterNamed name: String) -> SNVideoFilter { + let filter:SNVideoFilter = self.copy() as! SNVideoFilter + // Load the video + // Apply the filtering to the video. + // Return the new video. + return filter + } + +} + +// MARK: - NSCopying protocol + +extension SNVideoFilter: NSCopying { + + public func copy(with zone: NSZone?) -> Any { + guard + let videoLocation = videoLocation + else { fatalError("The video location is mandatory") } + + let copy = SNVideoFilter(frame: frame, withVideoAt: videoLocation, withContentMode: contentMode) + copy.backgroundColor = self.backgroundColor + copy.filterName = filterName + + for s in stickers { + copy.stickers.append(s.copy() as! SNSticker) + } + return copy + } +}