Repository: matthewpalmer/Regift Branch: master Commit: 9873b4b6a2b7 Files: 20 Total size: 66.7 KB Directory structure: gitextract_6iebs8wl/ ├── .gitignore ├── .swift-version ├── .travis.yml ├── LICENSE.markdown ├── README.markdown ├── Regift/ │ ├── AVAssetImageGeneratorTimePoints.swift │ ├── Info.plist │ ├── Regift.h │ └── Regift.swift ├── Regift.podspec ├── Regift.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata/ │ └── xcschemes/ │ ├── Regift.xcscheme │ └── RegiftOSX.xcscheme ├── RegiftOSX/ │ ├── Info.plist │ └── RegiftOSX.h ├── RegiftOSXTests/ │ └── Info.plist └── RegiftTests/ ├── Info.plist └── RegiftTests.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # OS X .DS_Store # Xcode build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout profile *.moved-aside DerivedData *.hmap *.ipa ================================================ FILE: .swift-version ================================================ 5.0 ================================================ FILE: .travis.yml ================================================ # references: # * http://www.objc.io/issue-6/travis-ci.html # * https://github.com/supermarin/xcpretty#usage osx_image: xcode10.2 language: swift # cache: cocoapods # podfile: Example/Podfile # before_install: # - gem install cocoapods # Since Travis is not always on latest version # - pod install --project-directory=Example install: - gem install xcpretty --no-document --quiet script: - set -o pipefail && xcodebuild test -project Regift.xcodeproj/ -scheme Regift -destination 'platform=iOS Simulator,name=iPhone X' ONLY_ACTIVE_ARCH=NO | xcpretty -c - set -o pipefail && xcodebuild test -project Regift.xcodeproj/ -scheme RegiftOSX -destination 'platform=OS X,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c - pod lib lint --quick ================================================ FILE: LICENSE.markdown ================================================ The MIT License (MIT) Copyright (c) 2014 Matthew Palmer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.markdown ================================================ # Regift Easily convert a video to a GIF on iOS and OSX. [![Travis](https://travis-ci.org/matthewpalmer/Regift.svg?branch=master)](https://travis-ci.org/matthewpalmer/Regift) [![Version](https://img.shields.io/cocoapods/v/Regift.svg?style=flat)](http://cocoadocs.org/docsets/Regift) [![License](https://img.shields.io/cocoapods/l/Regift.svg?style=flat)](http://cocoadocs.org/docsets/Regift) [![Platform](https://img.shields.io/cocoapods/p/Regift.svg?style=flat)](http://cocoadocs.org/docsets/Regift) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)


🚀

I also make Rocket, an app that gives you Slack-style emoji everywhere on your Mac.
Demo image of Rocket





## Requirements - Xcode 10+ - iOS 11.1+ / macOS 10.12+ - Swfit 5.0+ ## Installation ### Cocoapods Regift is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile: ``` pod "Regift" ``` ### Carthage Regift is available through [Carthage](https://github.com/Carthage/Carthage). ``` github 'matthewpalmer/Regift' ``` ## Quick Start ```swift import Regift ``` Synchronous GIF creation: ```swift let videoURL = ... let frameCount = 16 let delayTime = Float(0.2) let loopCount = 0 // 0 means loop forever let regift = Regift(sourceFileURL: videoURL, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount) print("Gif saved to \(regift.createGif())") let startTime = Float(30) let duration = Float(15) let frameRate = 15 let trimmedRegift = Regift(sourceFileURL: URL, startTime: startTime, duration: duration, frameRate: frameRate, loopCount: loopCount) print("Gif saved to \(trimmedRegift.createGif())") ``` Asynchronous GIF creation: ```swift let videoURL = ... let frameCount = 16 let delayTime = Float(0.2) let loopCount = 0 // 0 means loop forever Regift.createGIFFromSource(videoURL, frameCount: frameCount, delayTime: delayTime) { (result) in print("Gif saved to \(result)") } let startTime = Float(30) let duration = Float(15) let frameRate = 15 Regift.createGIFFromSource(videoURL, startTime: startTime, duration: duration, frameRate: frameRate) { (result) in print("Gif saved to \(result)") } ``` ## Acknowledgements Thanks to [Rob Mayoff's Gist](https://gist.github.com/mayoff/4969104), without which this library wouldn't exist. My personal thanks to all of Regift’s contributors: * caughtinflux * samuelbeek * sebyddd * nakajijapan * dbburgess ================================================ FILE: Regift/AVAssetImageGeneratorTimePoints.swift ================================================ // // AVAssetImageGeneratorTimePoints.swift // Vivify // // Created by Aditya KD on 26/07/15. // Copyright (c) 2015 Giffage. All rights reserved. // import AVFoundation public extension AVAssetImageGenerator { func generateCGImagesAsynchronouslyForTimePoints(timePoints: [TimePoint], completionHandler: @escaping AVAssetImageGeneratorCompletionHandler) { let times = timePoints.map {timePoint in return NSValue(time: timePoint) } self.generateCGImagesAsynchronously(forTimes: times, completionHandler: completionHandler) } } ================================================ FILE: Regift/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Regift/Regift.h ================================================ // // Regift.h // Regift // // Created by Matthew Palmer on 27/12/2014. // Copyright (c) 2014 Matthew Palmer. All rights reserved. // #import #if TARGET_OS_WATCH #elif TARGET_OS_TV #elif TARGET_OS_IPHONE #import #elif TARGET_OS_MAC #import #endif //! Project version number for Regift. FOUNDATION_EXPORT double RegiftVersionNumber; //! Project version string for Regift. FOUNDATION_EXPORT const unsigned char RegiftVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: Regift/Regift.swift ================================================ // // Regift.swift // Regift // // Created by Matthew Palmer on 27/12/2014. // Copyright (c) 2014 Matthew Palmer. All rights reserved. // #if os(iOS) import UIKit import MobileCoreServices #elseif os(OSX) import AppKit #endif import ImageIO import AVFoundation public typealias TimePoint = CMTime public typealias ProgressHandler = (Double) -> Void /// Errors thrown by Regift public enum RegiftError: String, Error { case DestinationNotFound = "The temp file destination could not be created or found" case SourceFormatInvalid = "The source file does not appear to be a valid format" case AddFrameToDestination = "An error occurred when adding a frame to the destination" case DestinationFinalize = "An error occurred when finalizing the destination" } // Convenience struct for managing dispatch groups. private struct Group { let group = DispatchGroup() func enter() { group.enter() } func leave() { group.leave() } func wait() { let _ = group.wait(timeout: DispatchTime.distantFuture) } } /// Easily convert a video to a GIF. It can convert the whole thing, or you can choose a section to trim out. /// /// Synchronous Usage: /// /// let regift = Regift(sourceFileURL: movieFileURL, frameCount: 24, delayTime: 0.5, loopCount: 7) /// print(regift.createGif()) /// /// // OR /// /// let trimmedRegift = Regift(sourceFileURL: movieFileURL, startTime: 30, duration: 15, frameRate: 15) /// print(trimmedRegift.createGif()) /// /// Asynchronous Usage: /// /// let regift = Regift.createGIFFromSource(movieFileURL, frameCount: 24, delayTime: 0.5, loopCount: 7) { (result) in /// print(result) /// } /// /// // OR /// /// let trimmedRegift = Regift.createGIFFromSource(movieFileURL, startTime: 30, duration: 15, frameRate: 15, loopCount: 0) { (result) in /// print(result) /// } /// public struct Regift { // Static conversion methods, for convenient and easy-to-use API: /** Create a GIF from a movie stored at the given URL. This converts the whole video to a GIF meeting the requested output parameters. - parameters: - sourceFileURL: The source file to create the GIF from. - destinationFileURL: An optional destination file to write the GIF to. If you don't include this, a default path will be provided. - frameCount: The number of frames to include in the gif; each frame has the same duration and is spaced evenly over the video. - delayTime: The amount of time each frame exists for in the GIF. - loopCount: The number of times the GIF will repeat. This defaults to `0`, which means that the GIF will repeat infinitely. - size: The maximum size of generated GIF. This defaults to `nil`, which specifies the asset’s unscaled dimensions. Setting size will not change the image aspect ratio. - completion: A block that will be called when the GIF creation is completed. The `result` parameter provides the path to the file, or will be `nil` if there was an error. */ public static func createGIFFromSource( _ sourceFileURL: URL, destinationFileURL: URL? = nil, frameCount: Int, delayTime: Float, loopCount: Int = 0, size: CGSize? = nil, progress: ProgressHandler? = nil, completion: (_ result: URL?) -> Void) { let gift = Regift( sourceFileURL: sourceFileURL, destinationFileURL: destinationFileURL, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount, size: size, progress: progress ) completion(gift.createGif()) } /** Create a GIF from a movie stored at the given URL. This allows you to choose a start time and duration in the source material that will be used to create the GIF which meets the output parameters. - parameters: - sourceFileURL: The source file to create the GIF from. - destinationFileURL: An optional destination file to write the GIF to. If you don't include this, a default path will be provided. - startTime: The time in seconds in the source material at which you want the GIF to start. - duration: The duration in seconds that you want to pull from the source material. - frameRate: The desired frame rate of the outputted GIF. - loopCount: The number of times the GIF will repeat. This defaults to `0`, which means that the GIF will repeat infinitely. - size: The maximum size of generated GIF. This defaults to `nil`, which specifies the asset’s unscaled dimensions. Setting size will not change the image aspect ratio. - completion: A block that will be called when the GIF creation is completed. The `result` parameter provides the path to the file, or will be `nil` if there was an error. */ public static func createGIFFromSource( _ sourceFileURL: URL, destinationFileURL: URL? = nil, startTime: Float, duration: Float, frameRate: Int, loopCount: Int = 0, size: CGSize? = nil, progress: ProgressHandler? = nil, completion: (_ result: URL?) -> Void) { let gift = Regift( sourceFileURL: sourceFileURL, destinationFileURL: destinationFileURL, startTime: startTime, duration: duration, frameRate: frameRate, loopCount: loopCount, size: size, progress: progress ) completion(gift.createGif()) } public static func createGIF( fromAsset asset: AVAsset, destinationFileURL: URL? = nil, startTime: Float, duration: Float, frameRate: Int, loopCount: Int = 0, completion: (_ result: URL?) -> Void) { let gift = Regift( asset: asset, destinationFileURL: destinationFileURL, startTime: startTime, duration: duration, frameRate: frameRate, loopCount: loopCount ) completion(gift.createGif()) } private struct Constants { static let FileName = "regift.gif" static let TimeInterval: Int32 = 600 static let Tolerance = 0.01 } /// A reference to the asset we are converting. private var asset: AVAsset /// The url for the source file. private var sourceFileURL: URL? /// The point in time in the source which we will start from. private var startTime: Float = 0 /// The desired duration of the gif. private var duration: Float /// The total length of the movie, in seconds. private var movieLength: Float /// The number of frames we are going to use to create the gif. private let frameCount: Int /// The amount of time each frame will remain on screen in the gif. private let delayTime: Float /// The number of times the gif will loop (0 is infinite). private let loopCount: Int /// The destination path for the generated file. private var destinationFileURL: URL? /// The handler to inform you about the current GIF export progress private var progress: ProgressHandler? /// The maximum width/height for the generated file. fileprivate let size: CGSize? /** Create a GIF from a movie stored at the given URL. This converts the whole video to a GIF meeting the requested output parameters. - parameters: - sourceFileURL: The source file to create the GIF from. - destinationFileURL: An optional destination file to write the GIF to. If you don't include this, a default path will be provided. - frameCount: The number of frames to include in the gif; each frame has the same duration and is spaced evenly over the video. - delayTime: The amount of time each frame exists for in the GIF. - loopCount: The number of times the GIF will repeat. This defaults to `0`, which means that the GIF will repeat infinitely. - size: The maximum size of generated GIF. This defaults to `nil`, which specifies the asset’s unscaled dimensions. Setting size will not change the image aspect ratio. */ public init(sourceFileURL: URL, destinationFileURL: URL? = nil, frameCount: Int, delayTime: Float, loopCount: Int = 0, size: CGSize? = nil, progress: ProgressHandler? = nil) { self.sourceFileURL = sourceFileURL self.asset = AVURLAsset(url: sourceFileURL, options: nil) self.movieLength = Float(asset.duration.value) / Float(asset.duration.timescale) self.duration = movieLength self.delayTime = delayTime self.loopCount = loopCount self.destinationFileURL = destinationFileURL self.frameCount = frameCount self.size = size self.progress = progress } /** Create a GIF from a movie stored at the given URL. This allows you to choose a start time and duration in the source material that will be used to create the GIF which meets the output parameters. - parameters: - sourceFileURL: The source file to create the GIF from. - destinationFileURL: An optional destination file to write the GIF to. If you don't include this, a default path will be provided. - startTime: The time in seconds in the source material at which you want the GIF to start. - duration: The duration in seconds that you want to pull from the source material. - frameRate: The desired frame rate of the outputted GIF. - loopCount: The number of times the GIF will repeat. This defaults to `0`, which means that the GIF will repeat infinitely. - size: The maximum size of generated GIF. This defaults to `nil`, which specifies the asset’s unscaled dimensions. Setting size will not change the image aspect ratio. */ public init(sourceFileURL: URL, destinationFileURL: URL? = nil, startTime: Float, duration: Float, frameRate: Int, loopCount: Int = 0, size: CGSize? = nil, progress: ProgressHandler? = nil) { self.sourceFileURL = sourceFileURL self.asset = AVURLAsset(url: sourceFileURL, options: nil) self.destinationFileURL = destinationFileURL self.startTime = startTime self.duration = duration // The delay time is based on the desired framerate of the gif. self.delayTime = (1.0 / Float(frameRate)) // The frame count is based on the desired length and framerate of the gif. self.frameCount = Int(duration * Float(frameRate)) // The total length of the file, in seconds. self.movieLength = Float(asset.duration.value) / Float(asset.duration.timescale) self.loopCount = loopCount self.size = size self.progress = progress } public init(asset: AVAsset, destinationFileURL: URL? = nil, startTime: Float, duration: Float, frameRate: Int, loopCount: Int = 0, size: CGSize? = nil, progress: ProgressHandler? = nil) { self.asset = asset self.destinationFileURL = destinationFileURL self.startTime = startTime self.duration = duration self.delayTime = (1.0 / Float(frameRate)) self.frameCount = Int(duration * Float(frameRate)) self.movieLength = Float(asset.duration.value) / Float(asset.duration.timescale) self.loopCount = loopCount self.size = size self.progress = progress } /** Get the URL of the GIF created with the attributes provided in the initializer. - returns: The path to the created GIF, or `nil` if there was an error creating it. */ public func createGif() -> URL? { let fileProperties = [kCGImagePropertyGIFDictionary as String:[ kCGImagePropertyGIFLoopCount as String: NSNumber(value: Int32(loopCount) as Int32)], kCGImagePropertyGIFHasGlobalColorMap as String: NSValue(nonretainedObject: true) ] as [String : Any] let frameProperties = [ kCGImagePropertyGIFDictionary as String:[ kCGImagePropertyGIFDelayTime as String:delayTime ] ] // How far along the video track we want to move, in seconds. let increment = Float(duration) / Float(frameCount) // Add each of the frames to the buffer var timePoints: [TimePoint] = [] for frameNumber in 0 ..< frameCount { let seconds: Float64 = Float64(startTime) + (Float64(increment) * Float64(frameNumber)) let time = CMTimeMakeWithSeconds(seconds, preferredTimescale: Constants.TimeInterval) timePoints.append(time) } do { return try createGIFForTimePoints(timePoints, fileProperties: fileProperties as [String : AnyObject], frameProperties: frameProperties as [String : AnyObject], frameCount: frameCount, size: size) } catch { return nil } } /** Create a GIF using the given time points in a movie file stored in this Regift's `asset`. - parameters: - timePoints: timePoints An array of `TimePoint`s (which are typealiased `CMTime`s) to use as the frames in the GIF. - fileProperties: The desired attributes of the resulting GIF. - frameProperties: The desired attributes of each frame in the resulting GIF. - frameCount: The desired number of frames for the GIF. *NOTE: This seems redundant to me, as `timePoints.count` should really be what we are after, but I'm hesitant to change the API here.* - size: The maximum size of generated GIF. This defaults to `nil`, which specifies the asset’s unscaled dimensions. Setting size will not change the image aspect ratio. - returns: The path to the created GIF, or `nil` if there was an error creating it. */ public func createGIFForTimePoints(_ timePoints: [TimePoint], fileProperties: [String: AnyObject], frameProperties: [String: AnyObject], frameCount: Int, size: CGSize? = nil) throws -> URL { // Ensure the source media is a valid file. guard asset.tracks(withMediaCharacteristic: .visual).count > 0 else { throw RegiftError.SourceFormatInvalid } var fileURL:URL? if self.destinationFileURL != nil { fileURL = self.destinationFileURL } else { let temporaryFile = (NSTemporaryDirectory() as NSString).appendingPathComponent(Constants.FileName) fileURL = URL(fileURLWithPath: temporaryFile) } guard let destination = CGImageDestinationCreateWithURL(fileURL! as CFURL, kUTTypeGIF, frameCount, nil) else { throw RegiftError.DestinationNotFound } CGImageDestinationSetProperties(destination, fileProperties as CFDictionary) let generator = AVAssetImageGenerator(asset: asset) generator.appliesPreferredTrackTransform = true if let size = size { generator.maximumSize = size } let tolerance = CMTimeMakeWithSeconds(Constants.Tolerance, preferredTimescale: Constants.TimeInterval) generator.requestedTimeToleranceBefore = tolerance generator.requestedTimeToleranceAfter = tolerance // Transform timePoints to times for the async asset generator method. var times = [NSValue]() for time in timePoints { times.append(NSValue(time: time)) } // Create a dispatch group to force synchronous behavior on an asynchronous method. let gifGroup = Group() gifGroup.enter() var handledTimes: Double = 0 generator.generateCGImagesAsynchronously(forTimes: times, completionHandler: { (requestedTime, image, actualTime, result, error) in handledTimes += 1 guard let imageRef = image , error == nil else { print("An error occurred: \(String(describing: error)), image is \(String(describing: image))") if requestedTime == times.last?.timeValue { gifGroup.leave() } return } CGImageDestinationAddImage(destination, imageRef, frameProperties as CFDictionary) self.progress?(min(1.0, handledTimes/max(1.0, Double(times.count)))) if requestedTime == times.last?.timeValue { gifGroup.leave() } }) // Wait for the asynchronous generator to finish. gifGroup.wait() CGImageDestinationSetProperties(destination, fileProperties as CFDictionary) // Finalize the gif if !CGImageDestinationFinalize(destination) { throw RegiftError.DestinationFinalize } return fileURL! } } ================================================ FILE: Regift.podspec ================================================ Pod::Spec.new do |s| s.name = "Regift" s.version = "1.6.0" s.summary = "Regift helps you easily convert a video to a GIF on iOS." s.description = <<-DESC Regift helps you easily convert a video to a GIF on iOS. Create a gif from a given video URL, tweaking the frame count, delay time, and number of loops. DESC s.homepage = "https://github.com/matthewpalmer/Regift" s.license = 'MIT' s.author = { "matthewpalmer" => "matt@matthewpalmer.net" } s.source = { :git => "https://github.com/matthewpalmer/Regift.git", :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/_matthewpalmer' s.ios.deployment_target = '11.1' s.osx.deployment_target = '10.12' s.requires_arc = true s.source_files = 'Regift/*.{m,h,swift}' end ================================================ FILE: Regift.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 0E0C3BC61A4E9A7D00325FF0 /* Regift.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E0C3BC51A4E9A7D00325FF0 /* Regift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0E0C3BCC1A4E9A7D00325FF0 /* Regift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BC01A4E9A7D00325FF0 /* Regift.framework */; }; 0E0C3BD31A4E9A7D00325FF0 /* RegiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0C3BD21A4E9A7D00325FF0 /* RegiftTests.swift */; }; 0E0C3BDD1A4E9A9000325FF0 /* Regift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0C3BDC1A4E9A9000325FF0 /* Regift.swift */; }; 0E0C3BDF1A4E9C1900325FF0 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BDE1A4E9C1900325FF0 /* ImageIO.framework */; }; 0E0C3BE11A4E9E6400325FF0 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BE01A4E9E6400325FF0 /* MobileCoreServices.framework */; }; 0E0C3BE51A4EA2F100325FF0 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BE41A4EA2F100325FF0 /* AVFoundation.framework */; }; 0EB2CE501B807C2600854BDD /* regift-test-file.mov in Resources */ = {isa = PBXBuildFile; fileRef = 0EB2CE4F1B807C2600854BDD /* regift-test-file.mov */; }; AE9B5BA81D8FC0E500F22881 /* AVAssetImageGeneratorTimePoints.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE9B5BA71D8FC0E500F22881 /* AVAssetImageGeneratorTimePoints.swift */; }; DC50F2D61C82B858008518EC /* RegiftOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = DC50F2D51C82B858008518EC /* RegiftOSX.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC50F2DC1C82B8FD008518EC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BE41A4EA2F100325FF0 /* AVFoundation.framework */; }; DC50F2DD1C82B8FD008518EC /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0C3BDE1A4E9C1900325FF0 /* ImageIO.framework */; }; DC50F30E1C82C863008518EC /* RegiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0C3BD21A4E9A7D00325FF0 /* RegiftTests.swift */; }; DC50F3111C82CB3B008518EC /* Regift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0C3BDC1A4E9A9000325FF0 /* Regift.swift */; }; DC50F3141C82D2CC008518EC /* regift-test-file.mov in Resources */ = {isa = PBXBuildFile; fileRef = 0EB2CE4F1B807C2600854BDD /* regift-test-file.mov */; }; DC50F3151C82D2F9008518EC /* RegiftOSX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC50F2D31C82B858008518EC /* RegiftOSX.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 0E0C3BCD1A4E9A7D00325FF0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0E0C3BB71A4E9A7D00325FF0 /* Project object */; proxyType = 1; remoteGlobalIDString = 0E0C3BBF1A4E9A7D00325FF0; remoteInfo = Regift; }; DC50F3091C82C85B008518EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0E0C3BB71A4E9A7D00325FF0 /* Project object */; proxyType = 1; remoteGlobalIDString = DC50F2D21C82B858008518EC; remoteInfo = RegiftOSX; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 0E0C3BC01A4E9A7D00325FF0 /* Regift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Regift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0E0C3BC41A4E9A7D00325FF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0E0C3BC51A4E9A7D00325FF0 /* Regift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Regift.h; sourceTree = ""; }; 0E0C3BCB1A4E9A7D00325FF0 /* RegiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RegiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0E0C3BD11A4E9A7D00325FF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0E0C3BD21A4E9A7D00325FF0 /* RegiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegiftTests.swift; sourceTree = ""; }; 0E0C3BDC1A4E9A9000325FF0 /* Regift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regift.swift; sourceTree = ""; }; 0E0C3BDE1A4E9C1900325FF0 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; 0E0C3BE01A4E9E6400325FF0 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 0E0C3BE21A4EA2A400325FF0 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 0E0C3BE41A4EA2F100325FF0 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 0EB2CE4F1B807C2600854BDD /* regift-test-file.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = "regift-test-file.mov"; sourceTree = ""; }; AE9B5BA71D8FC0E500F22881 /* AVAssetImageGeneratorTimePoints.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVAssetImageGeneratorTimePoints.swift; sourceTree = ""; }; DC50F2D31C82B858008518EC /* RegiftOSX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RegiftOSX.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC50F2D51C82B858008518EC /* RegiftOSX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegiftOSX.h; sourceTree = ""; }; DC50F2D71C82B858008518EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DC50F3031C82C85B008518EC /* RegiftOSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RegiftOSXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DC50F3071C82C85B008518EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0E0C3BBC1A4E9A7D00325FF0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0E0C3BE51A4EA2F100325FF0 /* AVFoundation.framework in Frameworks */, 0E0C3BE11A4E9E6400325FF0 /* MobileCoreServices.framework in Frameworks */, 0E0C3BDF1A4E9C1900325FF0 /* ImageIO.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 0E0C3BC81A4E9A7D00325FF0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0E0C3BCC1A4E9A7D00325FF0 /* Regift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F2CF1C82B858008518EC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DC50F2DD1C82B8FD008518EC /* ImageIO.framework in Frameworks */, DC50F2DC1C82B8FD008518EC /* AVFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F3001C82C85B008518EC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DC50F3151C82D2F9008518EC /* RegiftOSX.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0E0C3BB61A4E9A7D00325FF0 = { isa = PBXGroup; children = ( 0E0C3BC21A4E9A7D00325FF0 /* Regift */, 0E0C3BCF1A4E9A7D00325FF0 /* RegiftTests */, DC50F2D41C82B858008518EC /* RegiftOSX */, DC50F3041C82C85B008518EC /* RegiftOSXTests */, 0E0C3BC11A4E9A7D00325FF0 /* Products */, DC50F2DB1C82B8B0008518EC /* frameworks */, ); sourceTree = ""; }; 0E0C3BC11A4E9A7D00325FF0 /* Products */ = { isa = PBXGroup; children = ( 0E0C3BC01A4E9A7D00325FF0 /* Regift.framework */, 0E0C3BCB1A4E9A7D00325FF0 /* RegiftTests.xctest */, DC50F2D31C82B858008518EC /* RegiftOSX.framework */, DC50F3031C82C85B008518EC /* RegiftOSXTests.xctest */, ); name = Products; sourceTree = ""; }; 0E0C3BC21A4E9A7D00325FF0 /* Regift */ = { isa = PBXGroup; children = ( 0E0C3BC51A4E9A7D00325FF0 /* Regift.h */, 0E0C3BDC1A4E9A9000325FF0 /* Regift.swift */, AE9B5BA71D8FC0E500F22881 /* AVAssetImageGeneratorTimePoints.swift */, 0E0C3BC31A4E9A7D00325FF0 /* Supporting Files */, ); path = Regift; sourceTree = ""; }; 0E0C3BC31A4E9A7D00325FF0 /* Supporting Files */ = { isa = PBXGroup; children = ( 0E0C3BC41A4E9A7D00325FF0 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 0E0C3BCF1A4E9A7D00325FF0 /* RegiftTests */ = { isa = PBXGroup; children = ( 0E0C3BD21A4E9A7D00325FF0 /* RegiftTests.swift */, 0E0C3BD01A4E9A7D00325FF0 /* Supporting Files */, ); path = RegiftTests; sourceTree = ""; }; 0E0C3BD01A4E9A7D00325FF0 /* Supporting Files */ = { isa = PBXGroup; children = ( 0EB2CE4F1B807C2600854BDD /* regift-test-file.mov */, 0E0C3BD11A4E9A7D00325FF0 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; DC50F2D41C82B858008518EC /* RegiftOSX */ = { isa = PBXGroup; children = ( DC50F2D51C82B858008518EC /* RegiftOSX.h */, DC50F2D71C82B858008518EC /* Info.plist */, ); path = RegiftOSX; sourceTree = ""; }; DC50F2DB1C82B8B0008518EC /* frameworks */ = { isa = PBXGroup; children = ( 0E0C3BE41A4EA2F100325FF0 /* AVFoundation.framework */, 0E0C3BE21A4EA2A400325FF0 /* AssetsLibrary.framework */, 0E0C3BE01A4E9E6400325FF0 /* MobileCoreServices.framework */, 0E0C3BDE1A4E9C1900325FF0 /* ImageIO.framework */, ); name = frameworks; sourceTree = ""; }; DC50F3041C82C85B008518EC /* RegiftOSXTests */ = { isa = PBXGroup; children = ( DC50F3071C82C85B008518EC /* Info.plist */, ); path = RegiftOSXTests; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 0E0C3BBD1A4E9A7D00325FF0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 0E0C3BC61A4E9A7D00325FF0 /* Regift.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F2D01C82B858008518EC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( DC50F2D61C82B858008518EC /* RegiftOSX.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 0E0C3BBF1A4E9A7D00325FF0 /* Regift */ = { isa = PBXNativeTarget; buildConfigurationList = 0E0C3BD61A4E9A7D00325FF0 /* Build configuration list for PBXNativeTarget "Regift" */; buildPhases = ( 0E0C3BBB1A4E9A7D00325FF0 /* Sources */, 0E0C3BBC1A4E9A7D00325FF0 /* Frameworks */, 0E0C3BBD1A4E9A7D00325FF0 /* Headers */, 0E0C3BBE1A4E9A7D00325FF0 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Regift; productName = Regift; productReference = 0E0C3BC01A4E9A7D00325FF0 /* Regift.framework */; productType = "com.apple.product-type.framework"; }; 0E0C3BCA1A4E9A7D00325FF0 /* RegiftTests */ = { isa = PBXNativeTarget; buildConfigurationList = 0E0C3BD91A4E9A7D00325FF0 /* Build configuration list for PBXNativeTarget "RegiftTests" */; buildPhases = ( 0E0C3BC71A4E9A7D00325FF0 /* Sources */, 0E0C3BC81A4E9A7D00325FF0 /* Frameworks */, 0E0C3BC91A4E9A7D00325FF0 /* Resources */, ); buildRules = ( ); dependencies = ( 0E0C3BCE1A4E9A7D00325FF0 /* PBXTargetDependency */, ); name = RegiftTests; productName = RegiftTests; productReference = 0E0C3BCB1A4E9A7D00325FF0 /* RegiftTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; DC50F2D21C82B858008518EC /* RegiftOSX */ = { isa = PBXNativeTarget; buildConfigurationList = DC50F2D81C82B858008518EC /* Build configuration list for PBXNativeTarget "RegiftOSX" */; buildPhases = ( DC50F2CE1C82B858008518EC /* Sources */, DC50F2CF1C82B858008518EC /* Frameworks */, DC50F2D01C82B858008518EC /* Headers */, DC50F2D11C82B858008518EC /* Resources */, ); buildRules = ( ); dependencies = ( ); name = RegiftOSX; productName = RegiftOSX; productReference = DC50F2D31C82B858008518EC /* RegiftOSX.framework */; productType = "com.apple.product-type.framework"; }; DC50F3021C82C85B008518EC /* RegiftOSXTests */ = { isa = PBXNativeTarget; buildConfigurationList = DC50F30D1C82C85B008518EC /* Build configuration list for PBXNativeTarget "RegiftOSXTests" */; buildPhases = ( DC50F2FF1C82C85B008518EC /* Sources */, DC50F3001C82C85B008518EC /* Frameworks */, DC50F3011C82C85B008518EC /* Resources */, ); buildRules = ( ); dependencies = ( DC50F30A1C82C85B008518EC /* PBXTargetDependency */, ); name = RegiftOSXTests; productName = RegiftOSXTests; productReference = DC50F3031C82C85B008518EC /* RegiftOSXTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0E0C3BB71A4E9A7D00325FF0 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Matthew Palmer"; TargetAttributes = { 0E0C3BBF1A4E9A7D00325FF0 = { CreatedOnToolsVersion = 6.1.1; LastSwiftMigration = 0800; }; 0E0C3BCA1A4E9A7D00325FF0 = { CreatedOnToolsVersion = 6.1.1; LastSwiftMigration = 0800; }; DC50F2D21C82B858008518EC = { CreatedOnToolsVersion = 7.2.1; LastSwiftMigration = 0800; }; DC50F3021C82C85B008518EC = { CreatedOnToolsVersion = 7.2.1; LastSwiftMigration = 0800; }; }; }; buildConfigurationList = 0E0C3BBA1A4E9A7D00325FF0 /* Build configuration list for PBXProject "Regift" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 0E0C3BB61A4E9A7D00325FF0; productRefGroup = 0E0C3BC11A4E9A7D00325FF0 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0E0C3BBF1A4E9A7D00325FF0 /* Regift */, DC50F2D21C82B858008518EC /* RegiftOSX */, 0E0C3BCA1A4E9A7D00325FF0 /* RegiftTests */, DC50F3021C82C85B008518EC /* RegiftOSXTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 0E0C3BBE1A4E9A7D00325FF0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 0E0C3BC91A4E9A7D00325FF0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0EB2CE501B807C2600854BDD /* regift-test-file.mov in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F2D11C82B858008518EC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DC50F3011C82C85B008518EC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( DC50F3141C82D2CC008518EC /* regift-test-file.mov in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 0E0C3BBB1A4E9A7D00325FF0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0E0C3BDD1A4E9A9000325FF0 /* Regift.swift in Sources */, AE9B5BA81D8FC0E500F22881 /* AVAssetImageGeneratorTimePoints.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0E0C3BC71A4E9A7D00325FF0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0E0C3BD31A4E9A7D00325FF0 /* RegiftTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F2CE1C82B858008518EC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DC50F3111C82CB3B008518EC /* Regift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DC50F2FF1C82C85B008518EC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DC50F30E1C82C863008518EC /* RegiftTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 0E0C3BCE1A4E9A7D00325FF0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0E0C3BBF1A4E9A7D00325FF0 /* Regift */; targetProxy = 0E0C3BCD1A4E9A7D00325FF0 /* PBXContainerItemProxy */; }; DC50F30A1C82C85B008518EC /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC50F2D21C82B858008518EC /* RegiftOSX */; targetProxy = DC50F3091C82C85B008518EC /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 0E0C3BD41A4E9A7D00325FF0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.1; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 0E0C3BD51A4E9A7D00325FF0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.1; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 0E0C3BD71A4E9A7D00325FF0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Regift/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "net.matthewpalmer.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 0E0C3BD81A4E9A7D00325FF0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Regift/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "net.matthewpalmer.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; }; name = Release; }; 0E0C3BDA1A4E9A7D00325FF0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = RegiftTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "net.matthewpalmer.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; name = Debug; }; 0E0C3BDB1A4E9A7D00325FF0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = RegiftTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "net.matthewpalmer.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; name = Release; }; DC50F2D91C82B858008518EC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_TESTABILITY = YES; FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = RegiftOSX/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = net.matthewpalmer.Regift; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; DC50F2DA1C82B858008518EC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = RegiftOSX/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = net.matthewpalmer.Regift; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; }; name = Release; }; DC50F30B1C82C85B008518EC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = RegiftOSXTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = net.matthewpalmer.RegiftOSXTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Debug; }; DC50F30C1C82C85B008518EC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = RegiftOSXTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = net.matthewpalmer.RegiftOSXTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 0E0C3BBA1A4E9A7D00325FF0 /* Build configuration list for PBXProject "Regift" */ = { isa = XCConfigurationList; buildConfigurations = ( 0E0C3BD41A4E9A7D00325FF0 /* Debug */, 0E0C3BD51A4E9A7D00325FF0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0E0C3BD61A4E9A7D00325FF0 /* Build configuration list for PBXNativeTarget "Regift" */ = { isa = XCConfigurationList; buildConfigurations = ( 0E0C3BD71A4E9A7D00325FF0 /* Debug */, 0E0C3BD81A4E9A7D00325FF0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0E0C3BD91A4E9A7D00325FF0 /* Build configuration list for PBXNativeTarget "RegiftTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 0E0C3BDA1A4E9A7D00325FF0 /* Debug */, 0E0C3BDB1A4E9A7D00325FF0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DC50F2D81C82B858008518EC /* Build configuration list for PBXNativeTarget "RegiftOSX" */ = { isa = XCConfigurationList; buildConfigurations = ( DC50F2D91C82B858008518EC /* Debug */, DC50F2DA1C82B858008518EC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DC50F30D1C82C85B008518EC /* Build configuration list for PBXNativeTarget "RegiftOSXTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DC50F30B1C82C85B008518EC /* Debug */, DC50F30C1C82C85B008518EC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0E0C3BB71A4E9A7D00325FF0 /* Project object */; } ================================================ FILE: Regift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Regift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Regift.xcodeproj/xcshareddata/xcschemes/Regift.xcscheme ================================================ ================================================ FILE: Regift.xcodeproj/xcshareddata/xcschemes/RegiftOSX.xcscheme ================================================ ================================================ FILE: RegiftOSX/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2016 Matthew Palmer. All rights reserved. NSPrincipalClass ================================================ FILE: RegiftOSX/RegiftOSX.h ================================================ // // RegiftOSX.h // RegiftOSX // // Created by nakajijapan on 2016/02/28. // Copyright © 2016 Matthew Palmer. All rights reserved. // #import //! Project version number for RegiftOSX. FOUNDATION_EXPORT double RegiftOSXVersionNumber; //! Project version string for RegiftOSX. FOUNDATION_EXPORT const unsigned char RegiftOSXVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: RegiftOSXTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: RegiftTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: RegiftTests/RegiftTests.swift ================================================ // // RegiftTests.swift // RegiftTests // // Created by Matthew Palmer on 27/12/2014. // Copyright (c) 2014 Matthew Palmer. All rights reserved. // #if os(iOS) import UIKit import Regift #elseif os(OSX) import AppKit import RegiftOSX #endif import XCTest import ImageIO class RegiftTests: XCTestCase { var URL: Foundation.URL! override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. let testBundle = Bundle(for: type(of: self)) URL = testBundle.url(forResource: "regift-test-file", withExtension: "mov") XCTAssertNotNil(URL) } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } func testGIFIsCreated() { let regift = Regift(sourceFileURL: URL, frameCount: 16, delayTime: 0.2) let result = regift.createGif() XCTAssertNotNil(result, "The GIF URL should not be nil") XCTAssertTrue(FileManager.default.fileExists(atPath: result!.path)) let source = CGImageSourceCreateWithURL(result! as CFURL, nil) let count = CGImageSourceGetCount(source!) let type = CGImageSourceGetType(source!) let properties = CGImageSourceCopyProperties(source!, nil)! as NSDictionary let fileProperties = properties.object(forKey: kCGImagePropertyGIFDictionary as String) as! NSDictionary let loopCount = fileProperties.value(forKey: kCGImagePropertyGIFLoopCount as String) as! Int XCTAssertEqual(count, 16) XCTAssertEqual(type! as NSString, "com.compuserve.gif") XCTAssertEqual(loopCount, 0) (0.. () in let frameProperties = CGImageSourceCopyPropertiesAtIndex(source!, index, nil)! as NSDictionary let gifFrameProperties = frameProperties.object(forKey: kCGImagePropertyGIFDictionary as String) print(gifFrameProperties ?? "") let delayTime = ((gifFrameProperties as! NSDictionary)[kCGImagePropertyGIFDelayTime as String] as! NSNumber).floatValue XCTAssertEqual(delayTime, 0.2) } } func testGIFIsSaved() { let savedURL = Foundation.URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("test.gif")) let regift = Regift(sourceFileURL: URL, destinationFileURL: savedURL, frameCount: 16, delayTime: 0.2, progress: { (progress) in print(progress) }) let result = regift.createGif() XCTAssertNotNil(result, "The GIF URL should not be nil") XCTAssertTrue(savedURL.absoluteString == result?.absoluteString) XCTAssertTrue(FileManager.default.fileExists(atPath: result!.path)) } func testTrimmedGIFIsSaved() { let savedURL = Foundation.URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("test_trim.gif")) let regift = Regift(sourceFileURL: URL, destinationFileURL: savedURL, startTime: 1, duration: 2, frameRate: 15) let result = regift.createGif() XCTAssertNotNil(result, "The GIF URL should not be nil") XCTAssertTrue(savedURL.absoluteString == result?.absoluteString) XCTAssertTrue(FileManager.default.fileExists(atPath: result!.path)) } func testGIFIsNotCreated() { let regift = Regift(sourceFileURL: Foundation.URL(fileURLWithPath: ""), frameCount: 10, delayTime: 0.5) let result = regift.createGif() XCTAssertNil(result) } }