Last active
November 26, 2018 18:22
-
-
Save SheffieldKevin/7110704 to your computer and use it in GitHub Desktop.
I had far more difficulty getting the generation of gif animations working correctly using ImageIO and Core-Graphics aka Quartz on MacOS/iOS than should have reasonably been expected.
This file contains hidden or 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
// main.m | |
// creategif | |
// | |
// Created by Kevin Meaney on 21/10/2013. | |
// I've briefly blogged about it here: | |
// http://blog.yvs.eu.com/2013/10/creating-gif-animations-using-coreimagequartz | |
// The following code is all that is all the code needed for a creating a command line tool to generate | |
// a gif animation from image files. | |
// The main limitation with this code is that apart from the frame delay time of 0.1 second, every | |
// other frame delay time has to be a multiple of 0.5 seconds. There is no checking that the frame size | |
// of each image file is the same or resizing of frames to make them conform. | |
// I provide no warranty as to the operation of this code. | |
#import <Foundation/Foundation.h> | |
@import ImageIO; | |
void PrintUsage() | |
{ | |
printf("creategif - usage:\n"); | |
printf(" ./creategif [-parameter <value> ...], filename1, filename2, ...\n"); | |
printf(" Parameters are preceded by a -<parameterName>. The order of the parameters is unimportant.\n"); | |
printf(" All the input image filenames follow the parameters and their values.\n"); | |
printf(" You probably need to escape or quote paths especially if the paths includes spaces etc..\n"); | |
printf(" If the output file already exists then it will be overwritten if possible.\n"); | |
printf(" Available parameters are:\n"); | |
printf(" -outputfile <output file path which should finish with a gif extension>\n"); | |
printf(" -delaytime <should be a floating point number above 0.1>\n"); | |
// printf(" -unclampeddelaytime <should be a floating point number above 0.1>\n"); | |
printf(" Sample export lines:\n"); | |
printf(" ./creategif -outputfile blahblah.gif -delaytime 0.4 -unclampeddelaytime 0.4 image1.png image2.png image3.png image4.png\n"); | |
printf(" ./creategif -outputfile \"Users/ktam/gifs/blahblah.gif\" -delaytime 1.0 image1.png image2.png image3.png image4.png\n"); | |
} | |
BOOL GetFloatFromString(NSString *string, CGFloat *value) | |
{ | |
NSScanner *scanner = [[NSScanner alloc] initWithString:string]; | |
CGFloat floatVal; | |
BOOL gotValue = [scanner scanDouble:&floatVal]; | |
if (gotValue) | |
{ | |
*value = floatVal; | |
} | |
return gotValue; | |
} | |
NSMutableArray *inputImageList; | |
NSString *outFilePath; | |
CGFloat delayTime; | |
CGFloat unclampedDelayTime; | |
BOOL gotDelayTime = NO; | |
BOOL gotUnclampedDelayTime = NO; | |
bool GetArgs(int argc, const char **argv) // returns true if successful. | |
{ | |
bool success = true; | |
argv++; | |
argc--; | |
const char *args; | |
// Get the parameters | |
while (argc > 0 && **argv == '-') | |
{ | |
args = *argv; | |
argv++; | |
argc--; | |
if ( ! strcmp ( args, "-outputfile" ) ) | |
{ | |
outFilePath = @(*argv++); | |
argc--; | |
} | |
else if ( ! strcmp( args, "-delaytime" )) | |
{ | |
gotDelayTime = GetFloatFromString(@(*argv++), &delayTime); | |
argc--; | |
} | |
/* else if ( ! strcmp( args, "-unclampeddelaytime")) | |
{ | |
gotUnclampedDelayTime = GetFloatFromString(@(*argv++), &unclampedDelayTime); | |
argc--; | |
} | |
*/ | |
} | |
if (!(gotDelayTime || gotUnclampedDelayTime)) | |
success = false; | |
if (!outFilePath) | |
success = false; | |
// If we've got to the end of arguments and there are no input files then bail. | |
if (!success) | |
return success; | |
inputImageList = [[NSMutableArray alloc] initWithCapacity:0]; | |
// [inputImageList addObject:@(args)]; | |
// Finished getting parameters. Now get list of source files. 1 image per file. | |
while (argc > 0) | |
{ | |
args = *argv; | |
argv++; | |
argc--; | |
[inputImageList addObject:@(args)]; | |
} | |
if (!inputImageList || [inputImageList count] == 0) | |
success = false; | |
return success; | |
} | |
int main(int argc, const char * argv[]) | |
{ | |
@autoreleasepool | |
{ | |
if (!GetArgs(argc, argv)) | |
{ | |
PrintUsage(); | |
return 0; | |
} | |
NSDictionary *gifFileProps = @{ @"{GIF}" : @{ @"HasGlobalColorMap" : @YES, | |
@"LoopCount" : @(0) } }; | |
NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outFilePath isDirectory:NO]; | |
CGImageDestinationRef imageDest; | |
imageDest = CGImageDestinationCreateWithURL((__bridge CFURLRef)outputURL, | |
CFSTR("com.compuserve.gif"), | |
[inputImageList count], | |
(__bridge CFDictionaryRef)gifFileProps); | |
if (!imageDest) | |
{ | |
printf("Couldn't create image destination\n"); | |
return 0; | |
} | |
CGImageDestinationSetProperties(imageDest, | |
(__bridge CFDictionaryRef)gifFileProps); | |
for (NSString *inputFile in inputImageList) | |
{ | |
NSString *expandedString = [inputFile stringByExpandingTildeInPath]; | |
NSURL *sourceFile = [[NSURL alloc] initFileURLWithPath:expandedString | |
isDirectory:NO]; | |
CGImageSourceRef imageSource; | |
imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef)sourceFile, | |
NULL); | |
if (!imageSource) | |
{ | |
printf("Invalid source file path\n"); | |
return 0; | |
} | |
if (CGImageSourceGetCount(imageSource)) | |
{ | |
CGImageRef theImage; | |
theImage = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); | |
if (theImage) | |
{ | |
NSMutableDictionary *gifFrameProps; | |
gifFrameProps = [[NSMutableDictionary alloc] initWithCapacity:0]; | |
if (gotDelayTime) | |
[gifFrameProps setObject:@(delayTime) forKey:@"DelayTime"]; | |
// if (gotUnclampedDelayTime) | |
// [gifFrameProps setObject:@(unclampedDelayTime) | |
// forKey:@"UnclampedDelayTime"]; | |
NSDictionary *frameProps = @{ @"{GIF}" : gifFrameProps }; | |
CGImageDestinationAddImage(imageDest, theImage, | |
(__bridge CFDictionaryRef)frameProps); | |
CFRelease(theImage); | |
} | |
} | |
CFRelease(imageSource); | |
} | |
CGImageDestinationFinalize(imageDest); | |
CFRelease(imageDest); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment