Skip to content

Instantly share code, notes, and snippets.

@Coder-ACJHP
Last active April 1, 2022 07:55
Show Gist options
  • Save Coder-ACJHP/55a0940381cc0489ab8c352a3639d2e1 to your computer and use it in GitHub Desktop.
Save Coder-ACJHP/55a0940381cc0489ab8c352a3639d2e1 to your computer and use it in GitHub Desktop.
Gif splitter or frame extractor for IOS written by Swift 4
/*
MIT License
Copyright (c) 2018 toddheasley
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.
*/
//
// CGifManager.swift
// GifMaker
//
// Created by Coder ACJHP on 25.02.2019.
// Copyright © 2019 Coder ACJHP. All rights reserved.
//
import UIKit
import ImageIO
import MobileCoreServices
class CGifManager {
static let shared = CGifManager()
typealias SequenceCompletionHandler = ([UIImage]) -> ()
typealias GenerateCompletionHandler = (String?) -> ()
func getSequence(gifNamed: String, completionHandler: SequenceCompletionHandler) {
guard let bundleURL = Bundle.main
.url(forResource: gifNamed, withExtension: "gif") else {
print("This image named \"\(gifNamed)\" does not exist!"); return
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("Cannot turn image named \"\(gifNamed)\" into NSData"); return
}
let gifOptions = [
kCGImageSourceShouldAllowFloat as String : kCFBooleanFalse,
kCGImageSourceCreateThumbnailWithTransform as String : kCFBooleanFalse,
kCGImageSourceCreateThumbnailFromImageAlways as String : kCFBooleanFalse,
kCGImageSourceShouldCacheImmediately as String : kCFBooleanFalse,
] as CFDictionary
guard let imageSource = CGImageSourceCreateWithData(imageData as CFData, gifOptions) else {
debugPrint("Cannot create image source with data!"); return
}
let framesCount = CGImageSourceGetCount(imageSource)
var imageProperties = [CFDictionary]()
for i in 0 ..< framesCount {
guard let dict = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) else { continue }
imageProperties.append(dict)
}
var frameList: [UIImage] = []
let dispatchGroup = DispatchGroup()
for index in 0 ..< framesCount {
dispatchGroup.enter()
guard let cgImageRef = CGImageSourceCreateImageAtIndex(imageSource, index, imageProperties[index]) else { continue }
frameList.append(UIImage(cgImage: cgImageRef))
dispatchGroup.leave()
}
dispatchGroup.wait()
completionHandler(frameList)
}
// Copied from URL: https://stackoverflow.com/a/45648677/6296931 than modified
func generateGif(photos: [UIImage], filename: String, completionHandler: GenerateCompletionHandler) {
let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let path = documentsDirectoryPath.appending("/\(filename)")
let fileProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]] as CFDictionary
let gifProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.125]] as CFDictionary
let cfURL = URL(fileURLWithPath: path) as CFURL
if let destination = CGImageDestinationCreateWithURL(cfURL, kUTTypeGIF, photos.count, nil) {
CGImageDestinationSetProperties(destination, fileProperties)
for photo in photos {
CGImageDestinationAddImage(destination, photo.cgImage!, gifProperties)
}
if CGImageDestinationFinalize(destination) {
completionHandler(path)
} else {
completionHandler(nil)
}
} else {
completionHandler(nil)
}
}
}
/*
THIS FILE INCLUDING CODE FOR USAGE OF GIF SPLITTER
*/
fileprivate func duYourBest() {
// Define empty array to store gif frames
var tempImageList: [UIImage] = []
// Parameter: gifNamed = Gif file located in project files
// First split the gif into image sequence to work with it.
// Function: self.mask = Custom func applying mask to images (create your own logic)
CGifManager.getSequence(gifNamed: "space")?.forEach({ (maskImage) in
// If you like play with images (gif frames as UIImage) here
// Or like mine mask images and collect them in array
tempImageList.append(self.mask(withImage: maskImage, sourceImage: TestController.bgImage))
})
// Create .gif file from given image list
// I will use my tempImageList that edited at top
CGifManager.generateGif(photos: tempImageList, filename: "Coder.gif") { (filePath) in
// Handle errors
if filePath == nil {
let alertView = UIAlertController(title: "Error", message: "Cannot create gif, unknown error!", preferredStyle: .alert)
alertView.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
self.present(alertView, animated: true, completion: nil)
} else {
// My "Coder.gif" file created successfully (do your own stuff here)
// I'm gonna use image list again to show in UI as animated image
self.backgroundImage.animationImages = tempImageList
self.backgroundImage.animationDuration = 2.0
self.backgroundImage.startAnimating()
do {
// Here I will get our "gif" file that we created it and I will share it with activity (as "Coder.gif")
let shareData: Data = try Data(contentsOf: URL(fileURLWithPath: filePath!))
let activityViewController:UIActivityViewController = UIActivityViewController(activityItems: [shareData], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
} catch {
// Handle error thats occured because of converting file to data or something else
let alertView = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
alertView.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
self.present(alertView, animated: true, completion: nil)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment