Last active
April 1, 2022 07:55
-
-
Save Coder-ACJHP/55a0940381cc0489ab8c352a3639d2e1 to your computer and use it in GitHub Desktop.
Gif splitter or frame extractor for IOS written by Swift 4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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