├── .DS_Store ├── GIFCompression ├── .DS_Store ├── lib-gif-compression │ ├── .DS_Store │ ├── src │ │ ├── .DS_Store │ │ ├── strerror.c │ │ ├── inttypes.h │ │ ├── gif_compress.c │ │ ├── config.h │ │ ├── gifunopt.c │ │ ├── gifsicle.h │ │ ├── kcolor.h │ │ ├── gif.h │ │ ├── clp.h │ │ ├── merge.c │ │ ├── optimize.c │ │ ├── giffunc.c │ │ └── gifread.c │ └── include │ │ ├── .DS_Store │ │ └── gif_compress.h ├── Info.plist ├── GIFCompression.h └── GIFCompression.m ├── GIFLossyCompressExample ├── meme.gif ├── ViewController.h ├── AppDelegate.h ├── main.m ├── ViewController.m ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json └── AppDelegate.m ├── GIFCompression.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── xiaoyu.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcuserdata │ └── xiaoyu.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── GIFCompression.xcscheme └── project.pbxproj └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/.DS_Store -------------------------------------------------------------------------------- /GIFCompression/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFCompression/.DS_Store -------------------------------------------------------------------------------- /GIFLossyCompressExample/meme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFLossyCompressExample/meme.gif -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFCompression/lib-gif-compression/.DS_Store -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFCompression/lib-gif-compression/src/.DS_Store -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/include/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFCompression/lib-gif-compression/include/.DS_Store -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/project.xcworkspace/xcuserdata/xiaoyu.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/levinXiao/GIFLossyCompress/HEAD/GIFCompression.xcodeproj/project.xcworkspace/xcuserdata/xiaoyu.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/include/gif_compress.h: -------------------------------------------------------------------------------- 1 | // 2 | // gif_compress.h 3 | // GIFCompression 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | int gif_compress(int lossylevel, char* inpath, char* outpath); 10 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // GIFLossyCompressExample 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // GIFLossyCompressExample 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GIFLossyCompressExample 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/strerror.c: -------------------------------------------------------------------------------- 1 | /* Some operating systems don't have strerror. 2 | This file provides a definition which David Mazieres 3 | assures me works. */ 4 | 5 | #if HAVE_CONFIG_H 6 | # include 7 | #endif 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | char * 13 | strerror(int errno) 14 | { 15 | extern int sys_nerr; 16 | extern char *sys_errlist[]; 17 | if (errno < 0 || errno >= sys_nerr) 18 | return (char *)"bad error number"; 19 | else 20 | return sys_errlist[errno]; 21 | } 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/xcuserdata/xiaoyu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/xcuserdata/xiaoyu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GIFCompression.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | GIFLossyCompressExample.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | B822021B1FE7E8930057DC2C 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GIFLossyCompress 2 | 3 | ### How To Use 4 | 5 | 6 | ``` 7 | NSString *input = [[NSBundle mainBundle] pathForResource:@"meme" ofType:@"gif"]; 8 | 9 | NSString *dirtail = [NSString stringWithFormat:@"%@",@"/Documents/Images"]; 10 | NSString *dirfull = [NSHomeDirectory() stringByAppendingPathComponent:dirtail]; 11 | if (![[NSFileManager defaultManager] fileExistsAtPath:dirfull]) { 12 | [[NSFileManager defaultManager] createDirectoryAtPath:dirfull withIntermediateDirectories:YES attributes:nil error:nil]; 13 | } 14 | 15 | NSString *outpath = [[dirfull stringByAppendingPathComponent:@"meme2"] stringByAppendingPathExtension:@"gif"]; 16 | 17 | NSLog(@"out path :%@",outpath); 18 | 19 | GIFCompressionResult re = [GIFCompression compressGIFWithLossyLevel:80 inputPath:input outputPath:outpath]; 20 | NSLog(@"end result : %d",(long)re); 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/inttypes.h: -------------------------------------------------------------------------------- 1 | #ifndef LCDF_INTTYPES_H 2 | #define LCDF_INTTYPES_H 3 | /* Define known-width integer types. */ 4 | 5 | #ifdef HAVE_INTTYPES_H 6 | # include 7 | #elif defined(HAVE_SYS_TYPES_H) 8 | # include 9 | # ifdef HAVE_U_INT_TYPES 10 | typedef u_int8_t uint8_t; 11 | typedef u_int16_t uint16_t; 12 | typedef u_int32_t uint32_t; 13 | # endif 14 | #elif defined(_WIN32) 15 | typedef __int8 int8_t; 16 | typedef unsigned __int8 uint8_t; 17 | typedef __int16 int16_t; 18 | typedef unsigned __int16 uint16_t; 19 | typedef __int32 int32_t; 20 | typedef unsigned __int32 uint32_t; 21 | #endif 22 | 23 | #ifndef HAVE_UINTPTR_T 24 | # if SIZEOF_VOID_P == SIZEOF_UNSIGNED_LONG 25 | typedef unsigned long uintptr_t; 26 | # elif SIZEOF_VOID_P == SIZEOF_UNSIGNED_INT 27 | typedef unsigned int uintptr_t; 28 | # endif 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /GIFCompression/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /GIFCompression/GIFCompression.h: -------------------------------------------------------------------------------- 1 | // 2 | // GIFCompression.h 3 | // GIFCompression 4 | // 5 | // Created by xiaoyu on 2017/12/18. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, GIFCompressionResult) { 12 | GIFCompressionResultOK = 0,//无错误 13 | GIFCompressionResultErrorNotInputNameError = 1,//inputpath格式错误(nil或空字符) 14 | GIFCompressionResultErrorNotOutputNameError = 2,//outputpath格式错误(nil或空字符) 15 | GIFCompressionResultErrorNotFoundInput = 3,//没有找到inputpath 16 | GIFCompressionResultErrorInputNotGIF = 4,//inputpath文件不是gif文件 17 | GIFCompressionResultErrorCompress = 5,//压缩出问题 18 | }; 19 | 20 | @interface GIFCompression : NSObject 21 | 22 | + (GIFCompressionResult)compressGIFWithLossyLevel:(int)lossylevel inputPath:(NSString *)inputPath outputPath:(NSString *)outputPath; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/gif_compress.c: -------------------------------------------------------------------------------- 1 | // 2 | // gif_compress.c 3 | // GIFCompression 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #include "gifsicle.h" 10 | 11 | int gif_compress(int lossylevel, char* inpath, char* outpath) { 12 | // arg gifsicle 13 | // arg -O3 14 | // arg --lossy=80 15 | // arg -o 16 | // arg /Users/xiaoyu/Desktop/lossy-compressed.gif 17 | // arg /Users/xiaoyu/Desktop/meme.gif 18 | 19 | if (inpath == NULL) { 20 | printf("inputpath NULL \n"); 21 | return -1; 22 | }else{ 23 | printf("inputpath %s \n",inpath); 24 | } 25 | 26 | if (outpath == NULL) { 27 | printf("outpath NULL \n"); 28 | return -1; 29 | }else{ 30 | printf("outpath %s \n",outpath); 31 | } 32 | 33 | if (lossylevel < 0 || lossylevel > 200) { 34 | lossylevel = 80; 35 | } 36 | char lossylevelchar[25]; 37 | sprintf(lossylevelchar, "--lossy=%d", lossylevel); 38 | 39 | char* cmd[6]; 40 | cmd[0] = "gifsicle"; 41 | cmd[1] = "-O3"; 42 | cmd[2] = lossylevelchar; 43 | cmd[3] = "-o"; 44 | cmd[4] = outpath; 45 | cmd[5] = inpath; 46 | 47 | int result = oc_main(6, cmd); 48 | 49 | return result; 50 | } 51 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // GIFCompressExample 4 | // 5 | // Created by xiaoyu on 2017/12/18. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "GIFCompression.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view, typically from a nib. 22 | 23 | NSString *input = [[NSBundle mainBundle] pathForResource:@"meme" ofType:@"gif"]; 24 | 25 | NSString *dirtail = [NSString stringWithFormat:@"%@",@"/Documents/Images"]; 26 | NSString *dirfull = [NSHomeDirectory() stringByAppendingPathComponent:dirtail]; 27 | if (![[NSFileManager defaultManager] fileExistsAtPath:dirfull]) { 28 | [[NSFileManager defaultManager] createDirectoryAtPath:dirfull withIntermediateDirectories:YES attributes:nil error:nil]; 29 | } 30 | 31 | NSString *outpath = [[dirfull stringByAppendingPathComponent:@"meme2"] stringByAppendingPathExtension:@"gif"]; 32 | 33 | NSLog(@"out path :%@",outpath); 34 | 35 | GIFCompressionResult re = [GIFCompression compressGIFWithLossyLevel:80 inputPath:input outputPath:outpath]; 36 | NSLog(@"end result : %d",(long)re); 37 | } 38 | 39 | 40 | - (void)didReceiveMemoryWarning { 41 | [super didReceiveMemoryWarning]; 42 | // Dispose of any resources that can be recreated. 43 | } 44 | 45 | 46 | @end 47 | 48 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /GIFCompression/GIFCompression.m: -------------------------------------------------------------------------------- 1 | // 2 | // GIFCompression.m 3 | // GIFCompression 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GIFCompression.h" 11 | 12 | #include "gif_compress.h" 13 | 14 | @implementation GIFCompression 15 | 16 | + (GIFCompressionResult)compressGIFWithLossyLevel:(int)lossylevel inputPath:(NSString *)inputPath outputPath:(NSString *)outputPath { 17 | if (!inputPath || [inputPath isEqualToString:@""]) { 18 | return GIFCompressionResultErrorNotInputNameError; 19 | } 20 | 21 | if (!outputPath || [outputPath isEqualToString:@""]) { 22 | return GIFCompressionResultErrorNotOutputNameError; 23 | } 24 | 25 | inputPath = [inputPath stringByReplacingOccurrencesOfString:@"file://" withString:@""]; 26 | 27 | NSFileManager *fileManager = [NSFileManager defaultManager]; 28 | BOOL isExistInput = [fileManager fileExistsAtPath:inputPath]; 29 | if (!isExistInput) { 30 | return GIFCompressionResultErrorNotFoundInput; 31 | } 32 | 33 | NSData *inputData = [[NSData alloc] initWithContentsOfFile:inputPath]; 34 | uint8_t c; 35 | [inputData getBytes:&c length:1]; 36 | if (c != 0x47) { 37 | return GIFCompressionResultErrorInputNotGIF; 38 | } 39 | 40 | BOOL isExistOutput = [fileManager fileExistsAtPath:outputPath]; 41 | if (isExistOutput) { 42 | [fileManager removeItemAtPath:outputPath error:nil]; 43 | } 44 | 45 | char *inputChar = (char *)(inputPath.UTF8String); 46 | char *outputChar = (char *)(outputPath.UTF8String); 47 | 48 | int result = gif_compress(lossylevel, inputChar, outputChar); 49 | if (result == 0) { 50 | return GIFCompressionResultOK; 51 | } 52 | return GIFCompressionResultErrorCompress; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /GIFLossyCompressExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /GIFLossyCompressExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // GIFLossyCompressExample 4 | // 5 | // Created by xiaoyu on 2017/12/19. 6 | // Copyright © 2017年 lenovo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/xcuserdata/xiaoyu.xcuserdatad/xcschemes/GIFCompression.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | #ifndef GIFSICLE_CONFIG_H 5 | #define GIFSICLE_CONFIG_H 6 | 7 | /* Define to 1 if multithreading support is available. */ 8 | #define ENABLE_THREADS 1 9 | 10 | /* Define to the number of arguments to gettimeofday. */ 11 | #define GETTIMEOFDAY_PROTO 2 12 | 13 | /* Define if GIF LZW compression is off. */ 14 | /* #undef GIF_UNGIF */ 15 | 16 | /* Define to 1 if `ext_vector_type' vector types are usable. */ 17 | #define HAVE_EXT_VECTOR_TYPE_VECTOR_TYPES 1 18 | 19 | /* Define to 1 if the system has the type `int64_t'. */ 20 | #define HAVE_INT64_T 1 21 | 22 | /* Define to 1 if you have the header file. */ 23 | #define HAVE_INTTYPES_H 1 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #define HAVE_MEMORY_H 1 27 | 28 | /* Define to 1 if you have the `mkstemp' function. */ 29 | #define HAVE_MKSTEMP 1 30 | 31 | /* Define to 1 if you have the `pow' function. */ 32 | #define HAVE_POW 1 33 | 34 | /* Define to 1 if SIMD types should be used. */ 35 | #define HAVE_SIMD 1 36 | 37 | /* Define to 1 if you have the header file. */ 38 | #define HAVE_STDINT_H 1 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #define HAVE_STDLIB_H 1 42 | 43 | /* Define to 1 if you have the `strerror' function. */ 44 | #define HAVE_STRERROR 1 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #define HAVE_STRINGS_H 1 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #define HAVE_STRING_H 1 51 | 52 | /* Define to 1 if you have the `strtoul' function. */ 53 | #define HAVE_STRTOUL 1 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #define HAVE_SYS_SELECT_H 1 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #define HAVE_SYS_STAT_H 1 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #define HAVE_SYS_TIME_H 1 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #define HAVE_SYS_TYPES_H 1 66 | 67 | /* Define to 1 if you have the header file. */ 68 | #define HAVE_TIME_H 1 69 | 70 | /* Define to 1 if the system has the type `uint64_t'. */ 71 | #define HAVE_UINT64_T 1 72 | 73 | /* Define to 1 if the system has the type `uintptr_t'. */ 74 | #define HAVE_UINTPTR_T 1 75 | 76 | /* Define to 1 if you have the header file. */ 77 | #define HAVE_UNISTD_H 1 78 | 79 | /* Define if you have u_intXX_t types but not uintXX_t types. */ 80 | /* #undef HAVE_U_INT_TYPES */ 81 | 82 | /* Define to 1 if `vector_size' vector types are usable. */ 83 | /* #undef HAVE_VECTOR_SIZE_VECTOR_TYPES */ 84 | 85 | /* Define to 1 if you have the `__builtin_shufflevector' function. */ 86 | #define HAVE___BUILTIN_SHUFFLEVECTOR 1 87 | 88 | /* Define to 1 if you have the `__sync_add_and_fetch' function. */ 89 | #define HAVE___SYNC_ADD_AND_FETCH 1 90 | 91 | /* Define to write GIFs to stdout even when stdout is a terminal. */ 92 | /* #undef OUTPUT_GIF_TO_TERMINAL */ 93 | 94 | /* Name of package */ 95 | #define PACKAGE "gifsicle" 96 | 97 | /* Define to the address where bug reports for this package should be sent. */ 98 | #define PACKAGE_BUGREPORT "" 99 | 100 | /* Define to the full name of this package. */ 101 | #define PACKAGE_NAME "gifsicle" 102 | 103 | /* Define to the full name and version of this package. */ 104 | #define PACKAGE_STRING "gifsicle 1.88" 105 | 106 | /* Define to the one symbol short name of this package. */ 107 | #define PACKAGE_TARNAME "gifsicle" 108 | 109 | /* Define to the home page for this package. */ 110 | #define PACKAGE_URL "" 111 | 112 | /* Define to the version of this package. */ 113 | #define PACKAGE_VERSION "1.88" 114 | 115 | /* Pathname separator character ('/' on Unix). */ 116 | #define PATHNAME_SEPARATOR '/' 117 | 118 | /* Define to a function that returns a random number. */ 119 | #define RANDOM random 120 | 121 | /* The size of `float', as computed by sizeof. */ 122 | #define SIZEOF_FLOAT 4 123 | 124 | /* The size of `unsigned int', as computed by sizeof. */ 125 | #define SIZEOF_UNSIGNED_INT 4 126 | 127 | /* The size of `unsigned long', as computed by sizeof. */ 128 | #define SIZEOF_UNSIGNED_LONG 8 129 | 130 | /* The size of `void *', as computed by sizeof. */ 131 | #define SIZEOF_VOID_P 8 132 | 133 | /* Define to 1 if you have the ANSI C header files. */ 134 | #define STDC_HEADERS 1 135 | 136 | /* Version number of package */ 137 | #define VERSION "1.88" 138 | 139 | /* Define if X is not available. */ 140 | /* #undef X_DISPLAY_MISSING */ 141 | 142 | /* Define to empty if `const' does not conform to ANSI C. */ 143 | /* #undef const */ 144 | 145 | /* Define to `__inline__' or `__inline' if that's what the C compiler 146 | calls it, or to nothing if 'inline' is not supported under any name. */ 147 | #ifndef __cplusplus 148 | /* #undef inline */ 149 | #endif 150 | 151 | #include 152 | 153 | #ifdef __cplusplus 154 | extern "C" { 155 | #endif 156 | 157 | /* Use the clean-failing malloc library in fmalloc.c. */ 158 | #define GIF_ALLOCATOR_DEFINED 1 159 | #define Gif_Free free 160 | 161 | /* Prototype strerror if we don't have it. */ 162 | #ifndef HAVE_STRERROR 163 | char *strerror(int errno); 164 | #endif 165 | 166 | #ifdef __cplusplus 167 | } 168 | /* Get rid of a possible inline macro under C++. */ 169 | # define inline inline 170 | #endif 171 | 172 | /* Need _setmode under MS-DOS, to set stdin/stdout to binary mode */ 173 | /* Need _fsetmode under OS/2 for the same reason */ 174 | /* Windows has _isatty and _snprintf, not the normal versions */ 175 | #if defined(_MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(__DJGPP__) 176 | # include 177 | # include 178 | # define isatty _isatty 179 | # define snprintf _snprintf 180 | #endif 181 | 182 | #endif /* GIFSICLE_CONFIG_H */ 183 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/gifunopt.c: -------------------------------------------------------------------------------- 1 | /* gifunopt.c - Unoptimization function for the GIF library. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of the LCDF GIF library. 4 | 5 | The LCDF GIF library is free software. It is distributed under the GNU 6 | General Public License, version 2; you can copy, distribute, or alter it at 7 | will, as long as this notice is kept intact and this source code is made 8 | available. There is no warranty, express or implied. */ 9 | 10 | #if HAVE_CONFIG_H 11 | # include 12 | #endif 13 | #include "gif.h" 14 | #include 15 | #include 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #define TRANSPARENT 256 21 | 22 | static void 23 | put_image_in_screen(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) 24 | { 25 | int transparent = gfi->transparent; 26 | int x, y; 27 | int w = gfi->width; 28 | int h = gfi->height; 29 | if (gfi->left + w > gfs->screen_width) 30 | w = gfs->screen_width - gfi->left; 31 | if (gfi->top + h > gfs->screen_height) 32 | h = gfs->screen_height - gfi->top; 33 | 34 | for (y = 0; y < h; y++) { 35 | uint16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; 36 | uint8_t *line = gfi->img[y]; 37 | for (x = 0; x < w; x++, move++, line++) 38 | if (*line != transparent) 39 | *move = *line; 40 | } 41 | } 42 | 43 | 44 | static void 45 | put_background_in_screen(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) 46 | { 47 | uint16_t solid; 48 | int x, y; 49 | int w = gfi->width; 50 | int h = gfi->height; 51 | if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left; 52 | if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top; 53 | 54 | if (gfi->transparent < 0 && gfs->images[0]->transparent < 0 55 | && gfs->global && gfs->background < gfs->global->ncol) 56 | solid = gfs->background; 57 | else 58 | solid = TRANSPARENT; 59 | 60 | for (y = 0; y < h; y++) { 61 | uint16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; 62 | for (x = 0; x < w; x++, move++) 63 | *move = solid; 64 | } 65 | } 66 | 67 | 68 | static int 69 | create_image_data(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen, 70 | uint8_t *new_data, int *used_transparent) 71 | { 72 | int have[257]; 73 | int transparent = -1; 74 | unsigned pos, size = gfs->screen_width * gfs->screen_height; 75 | uint16_t *move; 76 | int i; 77 | 78 | /* mark colors used opaquely in the image */ 79 | assert(TRANSPARENT == 256); 80 | for (i = 0; i < 257; i++) 81 | have[i] = 0; 82 | for (pos = 0, move = screen; pos != size; ++pos, move++) 83 | have[*move] = 1; 84 | 85 | /* the new transparent color is a color unused in either */ 86 | if (have[TRANSPARENT]) { 87 | for (i = 0; i < 256 && transparent < 0; i++) 88 | if (!have[i]) 89 | transparent = i; 90 | if (transparent < 0) 91 | goto error; 92 | if (transparent >= gfs->global->ncol) { 93 | Gif_ReArray(gfs->global->col, Gif_Color, 256); 94 | if (!gfs->global->col) goto error; 95 | gfs->global->ncol = transparent + 1; 96 | } 97 | } 98 | 99 | /* map the wide image onto the new data */ 100 | *used_transparent = 0; 101 | for (pos = 0, move = screen; pos != size; ++pos, move++, new_data++) 102 | if (*move == TRANSPARENT) { 103 | *new_data = transparent; 104 | *used_transparent = 1; 105 | } else 106 | *new_data = *move; 107 | 108 | gfi->transparent = transparent; 109 | return 1; 110 | 111 | error: 112 | return 0; 113 | } 114 | 115 | 116 | static int 117 | unoptimize_image(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) 118 | { 119 | unsigned size = gfs->screen_width * gfs->screen_height; 120 | int used_transparent; 121 | uint8_t *new_data = Gif_NewArray(uint8_t, size); 122 | uint16_t *new_screen = screen; 123 | if (!new_data) return 0; 124 | 125 | /* Oops! May need to uncompress it */ 126 | Gif_UncompressImage(gfs, gfi); 127 | Gif_ReleaseCompressedImage(gfi); 128 | 129 | if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) { 130 | new_screen = Gif_NewArray(uint16_t, size); 131 | if (!new_screen) return 0; 132 | memcpy(new_screen, screen, size * sizeof(uint16_t)); 133 | } 134 | 135 | put_image_in_screen(gfs, gfi, new_screen); 136 | if (!create_image_data(gfs, gfi, new_screen, new_data, &used_transparent)) { 137 | Gif_DeleteArray(new_data); 138 | return 0; 139 | } 140 | 141 | if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) 142 | Gif_DeleteArray(new_screen); 143 | else if (gfi->disposal == GIF_DISPOSAL_BACKGROUND) 144 | put_background_in_screen(gfs, gfi, screen); 145 | 146 | gfi->left = 0; 147 | gfi->top = 0; 148 | gfi->width = gfs->screen_width; 149 | gfi->height = gfs->screen_height; 150 | gfi->disposal = used_transparent; 151 | Gif_SetUncompressedImage(gfi, new_data, Gif_Free, 0); 152 | 153 | return 1; 154 | } 155 | 156 | 157 | static int 158 | no_more_transparency(Gif_Image *gfi1, Gif_Image *gfi2) 159 | { 160 | int t1 = gfi1->transparent, t2 = gfi2->transparent, y; 161 | if (t1 < 0) 162 | return 1; 163 | for (y = 0; y < gfi1->height; ++y) { 164 | uint8_t *d1 = gfi1->img[y], *d2 = gfi2->img[y], *ed1 = d1 + gfi1->width; 165 | while (d1 < ed1) { 166 | if (*d1 == t1 && *d2 != t2) 167 | return 0; 168 | ++d1, ++d2; 169 | } 170 | } 171 | return 1; 172 | } 173 | 174 | 175 | int 176 | Gif_FullUnoptimize(Gif_Stream *gfs, int flags) 177 | { 178 | int ok = 1; 179 | int i; 180 | unsigned pos, size; 181 | uint16_t *screen; 182 | uint16_t background; 183 | Gif_Image *gfi; 184 | 185 | if (gfs->nimages < 1) return 1; 186 | for (i = 0; i < gfs->nimages; i++) 187 | if (gfs->images[i]->local) 188 | return 0; 189 | if (!gfs->global) 190 | return 0; 191 | 192 | Gif_CalculateScreenSize(gfs, 0); 193 | size = gfs->screen_width * gfs->screen_height; 194 | 195 | screen = Gif_NewArray(uint16_t, size); 196 | gfi = gfs->images[0]; 197 | if (gfi->transparent < 0 198 | && gfs->global && gfs->background < gfs->global->ncol) 199 | background = gfs->background; 200 | else 201 | background = TRANSPARENT; 202 | for (pos = 0; pos != size; ++pos) 203 | screen[pos] = background; 204 | 205 | for (i = 0; i < gfs->nimages; i++) 206 | if (!unoptimize_image(gfs, gfs->images[i], screen)) 207 | ok = 0; 208 | 209 | if (ok) { 210 | if (flags & GIF_UNOPTIMIZE_SIMPLEST_DISPOSAL) { 211 | /* set disposal based on use of transparency. 212 | If (every transparent pixel in frame i is also transparent in frame 213 | i - 1), then frame i - 1 gets disposal ASIS; otherwise, disposal 214 | BACKGROUND. */ 215 | for (i = 0; i < gfs->nimages; ++i) 216 | if (i == gfs->nimages - 1 217 | || no_more_transparency(gfs->images[i+1], gfs->images[i])) 218 | gfs->images[i]->disposal = GIF_DISPOSAL_NONE; 219 | else 220 | gfs->images[i]->disposal = GIF_DISPOSAL_BACKGROUND; 221 | } else 222 | for (i = 0; i < gfs->nimages; ++i) 223 | gfs->images[i]->disposal = GIF_DISPOSAL_BACKGROUND; 224 | } 225 | 226 | Gif_DeleteArray(screen); 227 | return ok; 228 | } 229 | 230 | int 231 | Gif_Unoptimize(Gif_Stream *gfs) 232 | { 233 | return Gif_FullUnoptimize(gfs, 0); 234 | } 235 | 236 | #ifdef __cplusplus 237 | } 238 | #endif 239 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/gifsicle.h: -------------------------------------------------------------------------------- 1 | /* gifsicle.h - Function declarations for gifsicle. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of gifsicle. 4 | 5 | Gifsicle is free software. It is distributed under the GNU Public License, 6 | version 2; you can copy, distribute, or alter it at will, as long 7 | as this notice is kept intact and this source code is made available. There 8 | is no warranty, express or implied. */ 9 | 10 | #ifndef GIFSICLE_H 11 | #define GIFSICLE_H 12 | #include "gif.h" 13 | #include "clp.h" 14 | #ifdef __GNUC__ 15 | #define NORETURN __attribute__ ((noreturn)) 16 | #define USED_ATTR __attribute__ ((used)) 17 | #else 18 | #define NORETURN 19 | #define USED_ATTR 20 | #endif 21 | 22 | typedef struct Gt_Frameset Gt_Frameset; 23 | typedef struct Gt_Crop Gt_Crop; 24 | typedef struct Gt_ColorTransform Gt_ColorTransform; 25 | 26 | #if ENABLE_THREADS 27 | #include 28 | extern pthread_mutex_t kd3_sort_lock; 29 | #endif 30 | 31 | typedef struct Gt_Frame { 32 | 33 | Gif_Stream *stream; 34 | Gif_Image *image; 35 | int use; 36 | 37 | const char *name; 38 | int no_name; 39 | Gif_Comment *comment; 40 | int no_comments; 41 | 42 | Gif_Color transparent; /* also background */ 43 | int interlacing; 44 | int left; 45 | int top; 46 | 47 | Gt_Crop *crop; 48 | int left_offset; 49 | int top_offset; 50 | 51 | int delay; 52 | int disposal; 53 | 54 | Gt_Frameset *nest; 55 | int explode_by_name; 56 | 57 | int no_extensions; 58 | int no_app_extensions; 59 | Gif_Extension *extensions; 60 | 61 | unsigned flip_horizontal: 1; 62 | unsigned flip_vertical: 1; 63 | unsigned info_flags: 3; 64 | unsigned position_is_offset: 1; 65 | unsigned total_crop: 1; 66 | unsigned rotation; 67 | 68 | const char *input_filename; 69 | 70 | } Gt_Frame; 71 | 72 | 73 | struct Gt_Frameset { 74 | int count; 75 | int cap; 76 | Gt_Frame *f; 77 | }; 78 | 79 | 80 | struct Gt_Crop { 81 | int ready; 82 | int transparent_edges; 83 | int spec_x; 84 | int spec_y; 85 | int spec_w; 86 | int spec_h; 87 | int x; 88 | int y; 89 | int w; 90 | int h; 91 | int left_offset; 92 | int top_offset; 93 | }; 94 | 95 | 96 | typedef void (*colormap_transform_func)(Gif_Colormap *, void *); 97 | 98 | struct Gt_ColorTransform { 99 | Gt_ColorTransform *prev; 100 | Gt_ColorTransform *next; 101 | colormap_transform_func func; 102 | void *data; 103 | }; 104 | 105 | 106 | typedef struct { 107 | 108 | const char *output_name; 109 | const char *active_output_name; 110 | 111 | int screen_width; 112 | int screen_height; 113 | 114 | Gif_Color background; 115 | int loopcount; 116 | 117 | int colormap_size; 118 | Gif_Colormap *colormap_fixed; 119 | int colormap_algorithm; 120 | int colormap_needs_transparency; 121 | int dither_type; 122 | const uint8_t* dither_data; 123 | const char* dither_name; 124 | int colormap_gamma_type; 125 | double colormap_gamma; 126 | 127 | int optimizing; 128 | 129 | int scaling; 130 | int resize_width; 131 | int resize_height; 132 | int resize_flags; 133 | double scale_x; 134 | double scale_y; 135 | int scale_method; 136 | int scale_colors; 137 | 138 | int conserve_memory; 139 | 140 | } Gt_OutputData; 141 | 142 | extern Gt_OutputData active_output_data; 143 | extern Clp_Parser* clp; 144 | 145 | #define GT_SCALING_NONE 0 146 | #define GT_SCALING_RESIZE 1 147 | #define GT_SCALING_SCALE 2 148 | 149 | #define GT_RESIZE_FIT 1 150 | #define GT_RESIZE_FIT_DOWN 2 151 | #define GT_RESIZE_FIT_UP 4 152 | #define GT_RESIZE_MIN_DIMEN 8 153 | 154 | #define SCALE_METHOD_POINT 0 155 | #define SCALE_METHOD_BOX 1 156 | #define SCALE_METHOD_MIX 2 157 | #define SCALE_METHOD_CATROM 3 158 | #define SCALE_METHOD_LANCZOS2 4 159 | #define SCALE_METHOD_LANCZOS3 5 160 | #define SCALE_METHOD_MITCHELL 6 161 | 162 | #define GT_OPT_MASK 0xFFFF 163 | #define GT_OPT_KEEPEMPTY 0x10000 164 | 165 | 166 | /***** 167 | * helper 168 | **/ 169 | 170 | static inline int 171 | constrain(int low, int x, int high) 172 | { 173 | return x < low ? low : (x < high ? x : high); 174 | } 175 | 176 | 177 | /***** 178 | * error & verbose 179 | **/ 180 | extern const char *program_name; 181 | extern int verbosing; 182 | extern int error_count; 183 | extern int no_warnings; 184 | extern int thread_count; 185 | extern Gif_CompressInfo gif_write_info; 186 | 187 | void fatal_error(const char* format, ...) NORETURN; 188 | void warning(int need_file, const char* format, ...); 189 | void lwarning(const char* landmark, const char* format, ...); 190 | void error(int need_file, const char* format, ...); 191 | void lerror(const char* landmark, const char* format, ...); 192 | void clp_error_handler(Clp_Parser *clp, const char *clp_message); 193 | void usage(void); 194 | void short_usage(void); 195 | 196 | void verbose_open(char, const char *); 197 | void verbose_close(char); 198 | void verbose_endline(void); 199 | 200 | const char* debug_color_str(const Gif_Color* gfc); 201 | 202 | #define EXIT_OK 0 203 | #define EXIT_ERR 1 204 | #define EXIT_USER_ERR 1 205 | 206 | /***** 207 | * info &c 208 | **/ 209 | #define INFO_COLORMAPS 1 210 | #define INFO_EXTENSIONS 2 211 | #define INFO_SIZES 4 212 | void stream_info(FILE *f, Gif_Stream *gfs, const char *filename, int flags); 213 | void image_info(FILE *f, Gif_Stream *gfs, Gif_Image *gfi, int flags); 214 | 215 | char *explode_filename(const char *filename, int number, 216 | const char *name, int max_nimg); 217 | 218 | /***** 219 | * merging images 220 | **/ 221 | void unmark_colors(Gif_Colormap *); 222 | void unmark_colors_2(Gif_Colormap *); 223 | void mark_used_colors(Gif_Stream *gfs, Gif_Image *gfi, Gt_Crop *crop, 224 | int compress_immediately); 225 | int find_color_index(Gif_Color *c, int nc, Gif_Color *); 226 | int merge_colormap_if_possible(Gif_Colormap *, Gif_Colormap *); 227 | 228 | extern int warn_local_colormaps; 229 | void merge_stream(Gif_Stream *dest, Gif_Stream *src, int no_comments); 230 | void merge_comments(Gif_Comment *destc, Gif_Comment *srcc); 231 | Gif_Image* merge_image(Gif_Stream* dest, Gif_Stream* src, Gif_Image* srci, 232 | Gt_Frame* srcfr, int same_compressed_ok); 233 | 234 | void optimize_fragments(Gif_Stream *, int optimizeness, int huge_stream); 235 | 236 | /***** 237 | * image/colormap transformations 238 | **/ 239 | Gif_Colormap *read_colormap_file(const char *, FILE *); 240 | void apply_color_transforms(Gt_ColorTransform *, Gif_Stream *); 241 | 242 | typedef void (*color_transform_func)(Gif_Colormap *, void *); 243 | Gt_ColorTransform *append_color_transform 244 | (Gt_ColorTransform *list, color_transform_func, void *); 245 | Gt_ColorTransform *delete_color_transforms 246 | (Gt_ColorTransform *list, color_transform_func); 247 | 248 | void color_change_transformer(Gif_Colormap *, void *); 249 | Gt_ColorTransform *append_color_change 250 | (Gt_ColorTransform *list, Gif_Color, Gif_Color); 251 | 252 | void pipe_color_transformer(Gif_Colormap *, void *); 253 | 254 | void combine_crop(Gt_Crop *dstcrop, const Gt_Crop *srccrop, const Gif_Image *gfi); 255 | int crop_image(Gif_Image* gfi, Gt_Frame* fr, int preserve_total_crop); 256 | 257 | void flip_image(Gif_Image* gfi, Gt_Frame* fr, int is_vert); 258 | void rotate_image(Gif_Image* gfi, Gt_Frame* fr, int rotation); 259 | void resize_dimensions(int* w, int* h, double new_width, double new_height, 260 | int flags); 261 | void resize_stream(Gif_Stream* gfs, double new_width, double new_height, 262 | int flags, int method, int scale_colors); 263 | 264 | /***** 265 | * quantization 266 | **/ 267 | #define KC_GAMMA_SRGB 0 268 | #define KC_GAMMA_NUMERIC 1 269 | void kc_set_gamma(int type, double gamma); 270 | 271 | #define COLORMAP_DIVERSITY 0 272 | #define COLORMAP_BLEND_DIVERSITY 1 273 | #define COLORMAP_MEDIAN_CUT 2 274 | 275 | enum { 276 | dither_none = 0, dither_default, dither_floyd_steinberg, 277 | dither_ordered, dither_ordered_new 278 | }; 279 | int set_dither_type(Gt_OutputData* od, const char* name); 280 | void colormap_stream(Gif_Stream*, Gif_Colormap*, Gt_OutputData*); 281 | 282 | /***** 283 | * parsing stuff 284 | **/ 285 | extern int frame_spec_1; 286 | extern int frame_spec_2; 287 | extern char * frame_spec_name; 288 | extern int dimensions_x; 289 | extern int dimensions_y; 290 | extern int position_x; 291 | extern int position_y; 292 | extern Gif_Color parsed_color; 293 | extern Gif_Color parsed_color2; 294 | extern double parsed_scale_factor_x; 295 | extern double parsed_scale_factor_y; 296 | 297 | int parse_frame_spec(Clp_Parser *, const char *, int, void *); 298 | int parse_dimensions(Clp_Parser *, const char *, int, void *); 299 | int parse_position(Clp_Parser *, const char *, int, void *); 300 | int parse_scale_factor(Clp_Parser *, const char *, int, void *); 301 | int parse_color(Clp_Parser *, const char *, int, void *); 302 | int parse_rectangle(Clp_Parser *, const char *, int, void *); 303 | int parse_two_colors(Clp_Parser *, const char *, int, void *); 304 | 305 | extern Gif_Stream *input; 306 | extern const char *input_name; 307 | 308 | void input_stream(const char *); 309 | void input_done(void); 310 | void output_frames(void); 311 | 312 | /***** 313 | * stuff with frames 314 | **/ 315 | extern Gt_Frame def_frame; 316 | #define FRAME(fs, i) ((fs)->f[i]) 317 | 318 | Gt_Frameset * new_frameset(int initial_cap); 319 | Gt_Frame* add_frame(Gt_Frameset*, Gif_Stream*, Gif_Image*); 320 | void clear_def_frame_once_options(void); 321 | 322 | Gif_Stream * merge_frame_interval(Gt_Frameset *, int f1, int f2, 323 | Gt_OutputData *, int compress, int *huge); 324 | void clear_frameset(Gt_Frameset *, int from); 325 | void blank_frameset(Gt_Frameset *, int from, int to, int delete_ob); 326 | 327 | /***** 328 | * mode 329 | **/ 330 | #define BLANK_MODE 0 331 | #define MERGING 1 332 | #define BATCHING 2 333 | #define EXPLODING 3 334 | #define INFOING 4 335 | #define DELETING 5 336 | #define INSERTING 6 337 | 338 | extern int mode; 339 | extern int nested_mode; 340 | 341 | 342 | /***** 343 | * edit by xiaoyu 344 | * 我自定义扩展添加了该方法 这个方法作为桥接去调用main方法 传入cmd 345 | **/ 346 | int oc_main(int argc, char *argv[]); 347 | 348 | #endif 349 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/kcolor.h: -------------------------------------------------------------------------------- 1 | /* kcolor.h - Color-oriented function declarations for gifsicle. 2 | Copyright (C) 2013-2015 Eddie Kohler, ekohler@gmail.com 3 | This file is part of gifsicle. 4 | 5 | Gifsicle is free software. It is distributed under the GNU Public License, 6 | version 2; you can copy, distribute, or alter it at will, as long 7 | as this notice is kept intact and this source code is made available. There 8 | is no warranty, express or implied. */ 9 | 10 | #ifndef GIFSICLE_KCOLOR_H 11 | #define GIFSICLE_KCOLOR_H 12 | #include "gif.h" 13 | #include 14 | 15 | /* kcolor: a 3D vector, each component has 15 bits of precision */ 16 | /* 15 bits means KC_MAX * KC_MAX always fits within a signed 32-bit 17 | integer, and a 3-D squared distance always fits within an unsigned 32-bit 18 | integer. */ 19 | #define KC_MAX 0x7FFF 20 | #define KC_WHOLE 0x8000 21 | #define KC_HALF 0x4000 22 | #define KC_QUARTER 0x2000 23 | #define KC_BITS 15 24 | typedef struct kcolor { 25 | int16_t a[3]; 26 | } kcolor; 27 | 28 | #undef min 29 | #undef max 30 | #define min(a, b) ((a) < (b) ? (a) : (b)) 31 | #define max(a, b) ((a) > (b) ? (a) : (b)) 32 | 33 | #define KC_CLAMPV(v) (max(0, min((v), KC_MAX))) 34 | 35 | typedef union kacolor { 36 | kcolor k; 37 | int16_t a[4]; 38 | #if HAVE_INT64_T 39 | int64_t q; /* to get better alignment */ 40 | #endif 41 | } kacolor; 42 | 43 | 44 | /* gamma_tables[0]: array of 256 gamma-conversion values 45 | gamma_tables[1]: array of 256 reverse gamma-conversion values */ 46 | extern uint16_t* gamma_tables[2]; 47 | 48 | 49 | /* set `*kc` to the gamma transformation of `a0/a1/a2` [RGB] */ 50 | static inline void kc_set8g(kcolor* kc, int a0, int a1, int a2) { 51 | kc->a[0] = gamma_tables[0][a0]; 52 | kc->a[1] = gamma_tables[0][a1]; 53 | kc->a[2] = gamma_tables[0][a2]; 54 | } 55 | 56 | /* return the gamma transformation of `a0/a1/a2` [RGB] */ 57 | static inline kcolor kc_make8g(int a0, int a1, int a2) { 58 | kcolor kc; 59 | kc_set8g(&kc, a0, a1, a2); 60 | return kc; 61 | } 62 | 63 | /* return the gamma transformation of `*gfc` */ 64 | static inline kcolor kc_makegfcg(const Gif_Color* gfc) { 65 | return kc_make8g(gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); 66 | } 67 | 68 | /* return the uncorrected representation of `a0/a1/a2` [RGB] */ 69 | static inline kcolor kc_make8ng(int a0, int a1, int a2) { 70 | kcolor kc; 71 | kc.a[0] = (a0 << 7) + (a0 >> 1); 72 | kc.a[1] = (a1 << 7) + (a1 >> 1); 73 | kc.a[2] = (a2 << 7) + (a2 >> 1); 74 | return kc; 75 | } 76 | 77 | /* return the kcolor representation of `*gfc` (no gamma transformation) */ 78 | static inline kcolor kc_makegfcng(const Gif_Color* gfc) { 79 | return kc_make8ng(gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); 80 | } 81 | 82 | /* return transparency */ 83 | static inline kacolor kac_transparent() { 84 | kacolor x; 85 | x.a[0] = x.a[1] = x.a[2] = x.a[3] = 0; 86 | return x; 87 | } 88 | 89 | /* return a hex color string definition for `x` */ 90 | const char* kc_debug_str(kcolor x); 91 | 92 | /* set `*x` to the reverse gamma transformation of `*x` */ 93 | void kc_revgamma_transform(kcolor* x); 94 | 95 | /* return the reverse gramma transformation of `*x` as a Gif_Color */ 96 | static inline Gif_Color kc_togfcg(const kcolor* x) { 97 | kcolor xx = *x; 98 | Gif_Color gfc; 99 | kc_revgamma_transform(&xx); 100 | gfc.gfc_red = (uint8_t) (xx.a[0] >> 7); 101 | gfc.gfc_green = (uint8_t) (xx.a[1] >> 7); 102 | gfc.gfc_blue = (uint8_t) (xx.a[2] >> 7); 103 | gfc.haspixel = 0; 104 | return gfc; 105 | } 106 | 107 | 108 | /* return the squared Euclidean distance between `*x` and `*y` */ 109 | static inline uint32_t kc_distance(const kcolor* x, const kcolor* y) { 110 | int32_t d0 = x->a[0] - y->a[0], d1 = x->a[1] - y->a[1], 111 | d2 = x->a[2] - y->a[2]; 112 | return d0 * d0 + d1 * d1 + d2 * d2; 113 | } 114 | 115 | /* return the luminance value for `*x`; result is between 0 and KC_MAX */ 116 | static inline int kc_luminance(const kcolor* x) { 117 | return (55 * x->a[0] + 183 * x->a[1] + 19 * x->a[2]) >> 8; 118 | } 119 | 120 | /* set `*x` to the grayscale version of `*x`, transformed by luminance */ 121 | static inline void kc_luminance_transform(kcolor* x) { 122 | /* For grayscale colormaps, use distance in luminance space instead of 123 | 124 | distance in RGB space. The weights for the R,G,B components in 125 | luminance space are 0.2126,0.7152,0.0722. (That's ITU primaries, which 126 | are compatible with sRGB; NTSC recommended our previous values, 127 | 0.299,0.587,0.114.) Using the proportional factors 55,183,19 we get a 128 | scaled gray value between 0 and 255 * 257; dividing by 256 gives us 129 | what we want. Thanks to Christian Kumpf, , for 130 | providing a patch.*/ 131 | x->a[0] = x->a[1] = x->a[2] = kc_luminance(x); 132 | } 133 | 134 | 135 | /* wkcolor: like kcolor, but components are 32 bits instead of 16 */ 136 | 137 | typedef struct wkcolor { 138 | int32_t a[3]; 139 | } wkcolor; 140 | 141 | static inline void wkc_clear(wkcolor* x) { 142 | x->a[0] = x->a[1] = x->a[2] = 0; 143 | } 144 | 145 | 146 | /* kd3_tree: kd-tree for 3 dimensions, indexing kcolors */ 147 | 148 | typedef struct kd3_tree kd3_tree; 149 | typedef struct kd3_treepos kd3_treepos; 150 | 151 | struct kd3_tree { 152 | kd3_treepos* tree; 153 | int ntree; 154 | int disabled; 155 | kcolor* ks; 156 | int nitems; 157 | int items_cap; 158 | int maxdepth; 159 | void (*transform)(kcolor*); 160 | unsigned* xradius; 161 | }; 162 | 163 | /* initialize `kd3` with the given color `transform` (may be NULL) */ 164 | void kd3_init(kd3_tree* kd3, void (*transform)(kcolor*)); 165 | 166 | /* free `kd3` */ 167 | void kd3_cleanup(kd3_tree* kd3); 168 | 169 | /* add the transformed color `k` to `*kd3` (do not apply `kd3->transform`). */ 170 | void kd3_add_transformed(kd3_tree* kd3, const kcolor* k); 171 | 172 | /* given 8-bit color `a0/a1/a2` (RGB), gamma-transform it, transform it 173 | by `kd3->transform` if necessary, and add it to `*kd3` */ 174 | void kd3_add8g(kd3_tree* kd3, int a0, int a1, int a2); 175 | 176 | /* set `kd3->xradius`. given color `i`, `kd3->xradius[i]` is the square of the 177 | color's uniquely owned neighborhood. 178 | If `kc_distance(&kd3->ks[i], &k) < kd3->xradius[i]`, then 179 | `kd3_closest_transformed(kd3, &k) == i`. */ 180 | void kd3_build_xradius(kd3_tree* kd3); 181 | 182 | /* build the actual kd-tree for `kd3`. must be called before kd3_closest. */ 183 | void kd3_build(kd3_tree* kd3); 184 | 185 | /* kd3_init + kd3_add8g for all colors in `gfcm` + kd3_build */ 186 | void kd3_init_build(kd3_tree* kd3, void (*transform)(kcolor*), 187 | const Gif_Colormap* gfcm); 188 | 189 | /* return the index of the color in `*kd3` closest to `k`. 190 | if `dist!=NULL`, store the distance from `k` to that index in `*dist`. */ 191 | int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, 192 | unsigned* dist); 193 | 194 | /* given 8-bit color `a0/a1/a2` (RGB), gamma-transform it, transform it by 195 | `kd3->transform` if necessary, and return the index of the color in 196 | `*kd3` closest to it. */ 197 | int kd3_closest8g(kd3_tree* kd3, int a0, int a1, int a2); 198 | 199 | /* disable color index `i` in `*kd3`: it will never be returned by 200 | `kd3_closest*` */ 201 | static inline void kd3_disable(kd3_tree* kd3, int i) { 202 | assert((unsigned) i < (unsigned) kd3->nitems); 203 | assert(kd3->disabled < 0 || kd3->disabled == i); 204 | kd3->disabled = i; 205 | } 206 | 207 | /* enable all color indexes in `*kd3` */ 208 | static inline void kd3_enable_all(kd3_tree* kd3) { 209 | kd3->disabled = -1; 210 | } 211 | 212 | 213 | typedef uint32_t kchist_count_t; 214 | typedef struct kchistitem { 215 | kacolor ka; 216 | kchist_count_t count; 217 | } kchistitem; 218 | 219 | typedef struct kchist { 220 | kchistitem* h; 221 | int n; 222 | int capacity; 223 | } kchist; 224 | 225 | void kchist_init(kchist* kch); 226 | void kchist_cleanup(kchist* kch); 227 | void kchist_make(kchist* kch, Gif_Stream* gfs, uint32_t* ntransp); 228 | kchistitem* kchist_add(kchist* kch, kcolor color, kchist_count_t count); 229 | void kchist_compress(kchist* kch); 230 | 231 | 232 | typedef struct { 233 | kchist* kch; 234 | int* closest; 235 | uint32_t* min_dist; 236 | uint32_t* min_dither_dist; 237 | int* chosen; 238 | int nchosen; 239 | } kcdiversity; 240 | 241 | void kcdiversity_init(kcdiversity* div, kchist* kch, int dodither); 242 | void kcdiversity_cleanup(kcdiversity* div); 243 | int kcdiversity_find_popular(kcdiversity* div); 244 | int kcdiversity_find_diverse(kcdiversity* div, double ditherweight); 245 | int kcdiversity_choose(kcdiversity* div, int chosen, int dodither); 246 | 247 | 248 | Gif_Colormap* colormap_blend_diversity(kchist* kch, Gt_OutputData* od); 249 | Gif_Colormap* colormap_flat_diversity(kchist* kch, Gt_OutputData* od); 250 | Gif_Colormap* colormap_median_cut(kchist* kch, Gt_OutputData* od); 251 | 252 | 253 | #if HAVE_SIMD && HAVE_VECTOR_SIZE_VECTOR_TYPES 254 | typedef float float4 __attribute__((vector_size (sizeof(float) * 4))); 255 | typedef int int4 __attribute__((vector_size (sizeof(int) * 4))); 256 | #elif HAVE_SIMD && HAVE_EXT_VECTOR_TYPE_VECTOR_TYPES 257 | typedef float float4 __attribute__((ext_vector_type (4))); 258 | #else 259 | typedef float float4[4]; 260 | #endif 261 | 262 | typedef union scale_color { 263 | float4 a; 264 | } scale_color; 265 | 266 | static inline void sc_clear(scale_color* x) { 267 | x->a[0] = x->a[1] = x->a[2] = x->a[3] = 0; 268 | } 269 | 270 | static inline scale_color sc_makekc(const kcolor* k) { 271 | scale_color sc; 272 | sc.a[0] = k->a[0]; 273 | sc.a[1] = k->a[1]; 274 | sc.a[2] = k->a[2]; 275 | sc.a[3] = KC_MAX; 276 | return sc; 277 | } 278 | 279 | static inline scale_color sc_make(float a0, float a1, float a2, float a3) { 280 | scale_color sc; 281 | sc.a[0] = a0; 282 | sc.a[1] = a1; 283 | sc.a[2] = a2; 284 | sc.a[3] = a3; 285 | return sc; 286 | } 287 | 288 | #if HAVE_SIMD 289 | # define SCVEC_ADDV(sc, sc2) (sc).a += (sc2).a 290 | # define SCVEC_MULV(sc, sc2) (sc).a *= (sc2).a 291 | # define SCVEC_MULF(sc, f) (sc).a *= (f) 292 | # define SCVEC_DIVF(sc, f) (sc).a /= (f) 293 | # define SCVEC_ADDVxF(sc, sc2, f) (sc).a += (sc2).a * (f) 294 | # if HAVE___BUILTIN_SHUFFLEVECTOR 295 | # define SCVEC_ROT3(out, sc) do { (out).a = __builtin_shufflevector((sc).a, (sc).a, 1, 2, 0, 3); } while (0) 296 | # else 297 | # define SCVEC_ROT3(out, sc) do { int4 shufmask__ = {1, 2, 0, 3}; (out).a = __builtin_shuffle((sc).a, shufmask__); } while (0) 298 | # endif 299 | #else 300 | # define SCVEC_FOREACH(t) do { int k__; for (k__ = 0; k__ != 4; ++k__) { t; } } while (0) 301 | # define SCVEC_ADDV(sc, sc2) SCVEC_FOREACH((sc).a[k__] += (sc2).a[k__]) 302 | # define SCVEC_MULV(sc, sc2) SCVEC_FOREACH((sc).a[k__] *= (sc2).a[k__]) 303 | # define SCVEC_MULF(sc, f) SCVEC_FOREACH((sc).a[k__] *= (f)) 304 | # define SCVEC_DIVF(sc, f) SCVEC_FOREACH((sc).a[k__] /= (f)) 305 | # define SCVEC_ADDVxF(sc, sc2, f) SCVEC_FOREACH((sc).a[k__] += (sc2).a[k__] * (f)) 306 | # define SCVEC_ROT3(out, sc) do { float __a0 = (sc).a[0]; (out).a[0] = (sc).a[1]; (out).a[1] = (sc).a[2]; (out).a[2] = __a0; (out).a[3] = (sc).a[3]; } while (0) 307 | #endif 308 | 309 | #endif 310 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/gif.h: -------------------------------------------------------------------------------- 1 | /* gif.h - Interface to the LCDF GIF library. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of the LCDF GIF library. 4 | 5 | The GIF library is free software. It is distributed under the GNU General 6 | Public License, version 2; you can copy, distribute, or alter it at will, 7 | as long as this notice is kept intact and this source code is made 8 | available. There is no warranty, express or implied. */ 9 | 10 | #ifndef LCDF_GIF_H /* -*- mode: c -*- */ 11 | #define LCDF_GIF_H 12 | #include 13 | #include 14 | #include "inttypes.h" 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | /* NOTE: You should define the types uint8_t, uint16_t and uint32_t before 20 | including this file, probably by #including . */ 21 | 22 | #define GIF_MAJOR_VERSION 2 23 | #define GIF_MINOR_VERSION 0 24 | #define GIF_VERSION "2.0" 25 | 26 | typedef struct Gif_Stream Gif_Stream; 27 | typedef struct Gif_Image Gif_Image; 28 | typedef struct Gif_Colormap Gif_Colormap; 29 | typedef struct Gif_Comment Gif_Comment; 30 | typedef struct Gif_Extension Gif_Extension; 31 | typedef struct Gif_Record Gif_Record; 32 | 33 | typedef uint16_t Gif_Code; 34 | #define GIF_MAX_CODE_BITS 12 35 | #define GIF_MAX_CODE 0x1000 36 | #define GIF_MAX_BLOCK 255 37 | 38 | 39 | /** GIF_STREAM **/ 40 | 41 | struct Gif_Stream { 42 | Gif_Image **images; 43 | int nimages; 44 | int imagescap; 45 | 46 | Gif_Colormap *global; 47 | uint16_t background; /* 256 means no background */ 48 | 49 | uint16_t screen_width; 50 | uint16_t screen_height; 51 | long loopcount; /* -1 means no loop count */ 52 | 53 | Gif_Comment* end_comment; 54 | Gif_Extension* end_extension_list; 55 | 56 | unsigned errors; 57 | 58 | int userflags; 59 | const char* landmark; 60 | int refcount; 61 | }; 62 | 63 | Gif_Stream * Gif_NewStream(void); 64 | void Gif_DeleteStream(Gif_Stream *); 65 | 66 | Gif_Stream * Gif_CopyStreamSkeleton(Gif_Stream *); 67 | Gif_Stream * Gif_CopyStreamImages(Gif_Stream *); 68 | 69 | #define Gif_ScreenWidth(gfs) ((gfs)->screen_width) 70 | #define Gif_ScreenHeight(gfs) ((gfs)->screen_height) 71 | #define Gif_ImageCount(gfs) ((gfs)->nimages) 72 | 73 | #define GIF_UNOPTIMIZE_SIMPLEST_DISPOSAL 1 74 | #define GIF_MAX_SCREEN_WIDTH 65535 75 | #define GIF_MAX_SCREEN_HEIGHT 65535 76 | 77 | void Gif_CalculateScreenSize(Gif_Stream *, int force); 78 | int Gif_Unoptimize(Gif_Stream *); 79 | int Gif_FullUnoptimize(Gif_Stream *, int flags); 80 | 81 | 82 | /** GIF_IMAGE **/ 83 | 84 | struct Gif_Image { 85 | uint16_t width; 86 | uint16_t height; 87 | 88 | uint8_t **img; /* img[y][x] == image byte (x,y) */ 89 | uint8_t *image_data; 90 | 91 | uint16_t left; 92 | uint16_t top; 93 | uint16_t delay; 94 | uint8_t disposal; 95 | uint8_t interlace; 96 | 97 | Gif_Colormap *local; 98 | short transparent; /* -1 means no transparent index */ 99 | 100 | uint16_t user_flags; 101 | 102 | char *identifier; 103 | Gif_Comment* comment; 104 | Gif_Extension* extension_list; 105 | 106 | void (*free_image_data)(void *); 107 | 108 | uint32_t compressed_len; 109 | uint8_t *compressed; 110 | void (*free_compressed)(void *); 111 | 112 | void *user_data; 113 | void (*free_user_data)(void *); 114 | int refcount; 115 | 116 | }; 117 | 118 | #define GIF_DISPOSAL_NONE 0 119 | #define GIF_DISPOSAL_ASIS 1 120 | #define GIF_DISPOSAL_BACKGROUND 2 121 | #define GIF_DISPOSAL_PREVIOUS 3 122 | 123 | Gif_Image * Gif_NewImage(void); 124 | void Gif_DeleteImage(Gif_Image *gfi); 125 | 126 | int Gif_AddImage(Gif_Stream *gfs, Gif_Image *gfi); 127 | void Gif_RemoveImage(Gif_Stream *gfs, int i); 128 | Gif_Image * Gif_CopyImage(Gif_Image *gfi); 129 | void Gif_MakeImageEmpty(Gif_Image* gfi); 130 | 131 | Gif_Image * Gif_GetImage(Gif_Stream *gfs, int i); 132 | Gif_Image * Gif_GetNamedImage(Gif_Stream *gfs, const char *name); 133 | int Gif_ImageNumber(Gif_Stream *gfs, Gif_Image *gfi); 134 | 135 | #define Gif_ImageWidth(gfi) ((gfi)->width) 136 | #define Gif_ImageHeight(gfi) ((gfi)->height) 137 | #define Gif_ImageDelay(gfi) ((gfi)->delay) 138 | #define Gif_ImageUserData(gfi) ((gfi)->userdata) 139 | #define Gif_SetImageUserData(gfi, v) ((gfi)->userdata = v) 140 | int Gif_ImageColorBound(const Gif_Image* gfi); 141 | 142 | typedef void (*Gif_ReadErrorHandler)(Gif_Stream* gfs, 143 | Gif_Image* gfi, 144 | int is_error, 145 | const char* error_text); 146 | 147 | typedef struct { 148 | int flags; 149 | int loss; 150 | void *padding[7]; 151 | } Gif_CompressInfo; 152 | 153 | #define Gif_UncompressImage(gfs, gfi) Gif_FullUncompressImage((gfs),(gfi),0) 154 | int Gif_FullUncompressImage(Gif_Stream* gfs, Gif_Image* gfi, 155 | Gif_ReadErrorHandler handler); 156 | int Gif_CompressImage(Gif_Stream *gfs, Gif_Image *gfi); 157 | int Gif_FullCompressImage(Gif_Stream *gfs, Gif_Image *gfi, 158 | const Gif_CompressInfo *gcinfo); 159 | void Gif_ReleaseUncompressedImage(Gif_Image *gfi); 160 | void Gif_ReleaseCompressedImage(Gif_Image *gfi); 161 | int Gif_SetUncompressedImage(Gif_Image *gfi, uint8_t *data, 162 | void (*free_data)(void *), int data_interlaced); 163 | int Gif_CreateUncompressedImage(Gif_Image* gfi, int data_interlaced); 164 | 165 | int Gif_ClipImage(Gif_Image *gfi, int l, int t, int w, int h); 166 | 167 | void Gif_InitCompressInfo(Gif_CompressInfo *gcinfo); 168 | 169 | 170 | /** GIF_COLORMAP **/ 171 | 172 | typedef struct { 173 | uint8_t haspixel; /* semantics assigned by user */ 174 | uint8_t gfc_red; /* red component (0-255) */ 175 | uint8_t gfc_green; /* green component (0-255) */ 176 | uint8_t gfc_blue; /* blue component (0-255) */ 177 | uint32_t pixel; /* semantics assigned by user */ 178 | } Gif_Color; 179 | 180 | 181 | struct Gif_Colormap { 182 | int ncol; 183 | int capacity; 184 | uint32_t userflags; 185 | int refcount; 186 | Gif_Color *col; 187 | }; 188 | 189 | Gif_Colormap * Gif_NewColormap(void); 190 | Gif_Colormap * Gif_NewFullColormap(int count, int capacity); 191 | void Gif_DeleteColormap(Gif_Colormap *); 192 | 193 | Gif_Colormap * Gif_CopyColormap(Gif_Colormap *); 194 | 195 | int Gif_ColorEq(Gif_Color *, Gif_Color *); 196 | #define GIF_COLOREQ(c1, c2) \ 197 | ((c1)->gfc_red==(c2)->gfc_red && (c1)->gfc_green==(c2)->gfc_green && \ 198 | (c1)->gfc_blue==(c2)->gfc_blue) 199 | #define GIF_SETCOLOR(c, r, g, b) \ 200 | ((c)->gfc_red = (r), (c)->gfc_green = (g), (c)->gfc_blue = (b)) 201 | 202 | int Gif_FindColor(Gif_Colormap *, Gif_Color *); 203 | int Gif_AddColor(Gif_Colormap *, Gif_Color *, int look_from); 204 | 205 | 206 | /** GIF_COMMENT **/ 207 | 208 | struct Gif_Comment { 209 | char **str; 210 | int *len; 211 | int count; 212 | int cap; 213 | }; 214 | 215 | Gif_Comment * Gif_NewComment(void); 216 | void Gif_DeleteComment(Gif_Comment *); 217 | int Gif_AddCommentTake(Gif_Comment *, char *, int); 218 | int Gif_AddComment(Gif_Comment *, const char *, int); 219 | 220 | 221 | /** GIF_EXTENSION **/ 222 | 223 | struct Gif_Extension { 224 | int kind; /* negative kinds are reserved */ 225 | char* appname; 226 | int applength; 227 | uint8_t* data; 228 | uint32_t length; 229 | int packetized; 230 | 231 | Gif_Stream *stream; 232 | Gif_Image *image; 233 | Gif_Extension *next; 234 | void (*free_data)(void *); 235 | }; 236 | 237 | 238 | Gif_Extension* Gif_NewExtension(int kind, const char* appname, int applength); 239 | void Gif_DeleteExtension(Gif_Extension* gfex); 240 | Gif_Extension* Gif_CopyExtension(Gif_Extension* gfex); 241 | int Gif_AddExtension(Gif_Stream* gfs, Gif_Image* gfi, 242 | Gif_Extension* gfex); 243 | 244 | 245 | /** READING AND WRITING **/ 246 | 247 | struct Gif_Record { 248 | const unsigned char *data; 249 | uint32_t length; 250 | }; 251 | 252 | #define GIF_READ_COMPRESSED 1 253 | #define GIF_READ_UNCOMPRESSED 2 254 | #define GIF_READ_CONST_RECORD 4 255 | #define GIF_READ_TRAILING_GARBAGE_OK 8 256 | #define GIF_WRITE_CAREFUL_MIN_CODE_SIZE 1 257 | #define GIF_WRITE_EAGER_CLEAR 2 258 | #define GIF_WRITE_OPTIMIZE 4 259 | #define GIF_WRITE_SHRINK 8 260 | 261 | void Gif_SetErrorHandler(Gif_ReadErrorHandler handler); 262 | Gif_Stream* Gif_ReadFile(FILE* f); 263 | Gif_Stream* Gif_FullReadFile(FILE* f, int flags, const char* landmark, 264 | Gif_ReadErrorHandler handler); 265 | Gif_Stream* Gif_ReadRecord(const Gif_Record* record); 266 | Gif_Stream* Gif_FullReadRecord(const Gif_Record* record, int flags, 267 | const char* landmark, 268 | Gif_ReadErrorHandler handler); 269 | int Gif_WriteFile(Gif_Stream *gfs, FILE *f); 270 | int Gif_FullWriteFile(Gif_Stream *gfs, 271 | const Gif_CompressInfo *gcinfo, FILE *f); 272 | 273 | #define Gif_ReadFile(f) Gif_FullReadFile((f),GIF_READ_UNCOMPRESSED,0,0) 274 | #define Gif_ReadRecord(r) Gif_FullReadRecord((r),GIF_READ_UNCOMPRESSED,0,0) 275 | #define Gif_CompressImage(s, i) Gif_FullCompressImage((s),(i),0) 276 | #define Gif_WriteFile(s, f) Gif_FullWriteFile((s),0,(f)) 277 | 278 | typedef struct Gif_Writer Gif_Writer; 279 | Gif_Writer* Gif_IncrementalWriteFileInit(Gif_Stream* gfs, const Gif_CompressInfo* gcinfo, FILE *f); 280 | int Gif_IncrementalWriteImage(Gif_Writer* grr, Gif_Stream* gfs, Gif_Image* gfi); 281 | int Gif_IncrementalWriteComplete(Gif_Writer* grr, Gif_Stream* gfs); 282 | 283 | 284 | /** HOOKS AND MISCELLANEOUS **/ 285 | 286 | int Gif_InterlaceLine(int y, int height); 287 | char * Gif_CopyString(const char *); 288 | 289 | #define GIF_T_STREAM (0) 290 | #define GIF_T_IMAGE (1) 291 | #define GIF_T_COLORMAP (2) 292 | typedef void (*Gif_DeletionHookFunc)(int, void *, void *); 293 | int Gif_AddDeletionHook(int, Gif_DeletionHookFunc, void *); 294 | void Gif_RemoveDeletionHook(int, Gif_DeletionHookFunc, void *); 295 | 296 | #ifdef GIF_DEBUGGING 297 | #define GIF_DEBUG(x) Gif_Debug x 298 | void Gif_Debug(char *x, ...); 299 | #else 300 | #define GIF_DEBUG(x) 301 | #endif 302 | 303 | void* Gif_Realloc(void* p, size_t s, size_t n, 304 | const char* file, int line); 305 | void Gif_Free(void* p); 306 | #if !GIF_ALLOCATOR_DEFINED 307 | # define Gif_Free free 308 | #endif 309 | 310 | #ifndef Gif_New 311 | # define Gif_New(t) ((t*) Gif_Realloc(0, sizeof(t), 1, __FILE__, __LINE__)) 312 | # define Gif_NewArray(t, n) ((t*) Gif_Realloc(0, sizeof(t), (n), __FILE__, __LINE__)) 313 | # define Gif_ReArray(p, t, n) ((p)=(t*) Gif_Realloc((void*) (p), sizeof(t), (n), __FILE__, __LINE__)) 314 | # define Gif_Delete(p) Gif_Free((void*) (p)) 315 | # define Gif_DeleteArray(p) Gif_Free((void*) (p)) 316 | #endif 317 | 318 | #ifdef __cplusplus 319 | } 320 | #endif 321 | #endif 322 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/clp.h: -------------------------------------------------------------------------------- 1 | /* -*- related-file-name: "../../liblcdf/clp.c" -*- */ 2 | #ifndef LCDF_CLP_H 3 | #define LCDF_CLP_H 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* clp.h - Public interface to CLP. 9 | * This file is part of CLP, the command line parser package. 10 | * 11 | * Copyright (c) 1997-2014 Eddie Kohler, ekohler@gmail.com 12 | * 13 | * CLP is free software. It is distributed under the GNU General Public 14 | * License, Version 2, or, alternatively and at your discretion, under the 15 | * more permissive (BSD-like) Click LICENSE file as described below. 16 | * 17 | * Permission is hereby granted, free of charge, to any person obtaining a 18 | * copy of this software and associated documentation files (the 19 | * "Software"), to deal in the Software without restriction, subject to the 20 | * conditions listed in the Click LICENSE file, which is available in full at 21 | * http://github.com/kohler/click/blob/master/LICENSE. The conditions 22 | * include: you must preserve this copyright notice, and you cannot mention 23 | * the copyright holders in advertising related to the Software without 24 | * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS 25 | * OR IMPLIED. This notice is a summary of the Click LICENSE file; the 26 | * license in that file is binding. */ 27 | 28 | #include 29 | #include 30 | 31 | typedef struct Clp_Option Clp_Option; 32 | typedef struct Clp_Parser Clp_Parser; 33 | typedef struct Clp_ParserState Clp_ParserState; 34 | 35 | 36 | /** @brief Option description. 37 | * 38 | * CLP users declare arrays of Clp_Option structures to specify what options 39 | * should be parsed. 40 | * @sa Clp_NewParser, Clp_SetOptions */ 41 | struct Clp_Option { 42 | const char *long_name; /**< Name of long option, or NULL if the option 43 | has no long name. */ 44 | int short_name; /**< Character defining short option, or 0 if 45 | the option has no short name. */ 46 | int option_id; /**< User-specified ID defining option, 47 | returned by Clp_Next. */ 48 | int val_type; /**< ID of option's value type, or 0 if option 49 | takes no value. */ 50 | int flags; /**< Option parsing flags. */ 51 | }; 52 | 53 | /** @name Value types 54 | * These values describe the type of an option's argument and are used in 55 | * the Clp_Option val_type field. For example, if an option took integers, its 56 | * Clp_Option structure would have val_type set to Clp_ValInt. */ 57 | /**@{*/ 58 | #define Clp_NoVal 0 /**< @brief Option takes no value. */ 59 | #define Clp_ValString 1 /**< @brief Option value is an 60 | arbitrary string. */ 61 | #define Clp_ValStringNotOption 2 /**< @brief Option value is a 62 | non-option string. 63 | 64 | See Clp_DisallowOptions. */ 65 | #define Clp_ValBool 3 /**< @brief Option value is a 66 | boolean. 67 | 68 | Accepts "true", "false", "yes", "no", "1", and "0", or any 69 | prefixes thereof. The match is case-insensitive. */ 70 | #define Clp_ValInt 4 /**< @brief Option value is a 71 | signed int. 72 | 73 | Accepts an optional "+" or "-" sign, followed by one or more 74 | digits. The digits may be include a "0x" or "0X" prefix, for 75 | a hexadecimal number, or a "0" prefix, for an octal number; 76 | otherwise it is decimal. */ 77 | #define Clp_ValUnsigned 5 /**< @brief Option value is an 78 | unsigned int. 79 | 80 | Accepts an optional "+" sign, followed by one or more 81 | digits. The digits may be include a "0x" or "0X" prefix, for 82 | a hexadecimal number, or a "0" prefix, for an octal number; 83 | otherwise it is decimal. */ 84 | #define Clp_ValLong 6 /**< @brief Option value is a 85 | signed long. */ 86 | #define Clp_ValUnsignedLong 7 /**< @brief Option value is an 87 | unsigned long. */ 88 | #define Clp_ValDouble 8 /**< @brief Option value is a 89 | double. 90 | Accepts a real number as defined by strtod(). */ 91 | #define Clp_ValFirstUser 10 /**< @brief Value types >= 92 | Clp_ValFirstUser are available 93 | for user types. */ 94 | /**@}*/ 95 | 96 | /** @name Option flags 97 | * These flags are used in the Clp_Option flags field. */ 98 | /**@{*/ 99 | #define Clp_Mandatory (1<<0) /**< @brief Option flag: value 100 | is mandatory. 101 | 102 | It is an error if the option has no value. This is the 103 | default if an option has arg_type != 0 and the Clp_Optional 104 | flag is not provided. */ 105 | #define Clp_Optional (1<<1) /**< @brief Option flag: value 106 | is optional. */ 107 | #define Clp_Negate (1<<2) /**< @brief Option flag: option 108 | may be negated. 109 | 110 | --no-[long_name] will be accepted in argument lists. */ 111 | #define Clp_OnlyNegated (1<<3) /**< @brief Option flag: option 112 | must be negated. 113 | 114 | --no-[long_name] will be accepted in argument lists, but 115 | --[long_name] will not. This is the default if long_name 116 | begins with "no-". */ 117 | #define Clp_PreferredMatch (1<<4) /**< @brief Option flag: prefer this 118 | option when matching. 119 | 120 | Prefixes of --[long_name] should map to this option, even if 121 | other options begin with --[long_name]. */ 122 | /**@}*/ 123 | 124 | /** @name Option character types 125 | * These flags are used in to define character types in Clp_SetOptionChar(). */ 126 | /**@{*/ 127 | /* Clp_NotOption 0 */ 128 | #define Clp_Short (1<<0) /**< @brief Option character begins 129 | a set of short options. */ 130 | #define Clp_Long (1<<1) /**< @brief Option character begins 131 | a long option. */ 132 | #define Clp_ShortNegated (1<<2) /**< @brief Option character begins 133 | a set of negated short options. */ 134 | #define Clp_LongNegated (1<<3) /**< @brief Option character begins 135 | a negated long option. */ 136 | #define Clp_LongImplicit (1<<4) /**< @brief Option character can begin 137 | a long option, and is part of that 138 | long option. */ 139 | /**@}*/ 140 | 141 | #define Clp_NotOption 0 /**< @brief Clp_Next value: argument 142 | was not an option. */ 143 | #define Clp_Done -1 /**< @brief Clp_Next value: there are 144 | no more arguments. */ 145 | #define Clp_BadOption -2 /**< @brief Clp_Next value: argument 146 | was an erroneous option. */ 147 | #define Clp_Error -3 /**< @brief Clp_Next value: internal 148 | CLP error. */ 149 | 150 | #define Clp_ValSize 40 /**< @brief Minimum size of the 151 | Clp_Parser val.cs field. */ 152 | #define Clp_ValIntSize 10 /**< @brief Minimum size of the 153 | Clp_Parser val.is field. */ 154 | 155 | 156 | /** @brief A value parsing function. 157 | * @param clp the parser 158 | * @param vstr the value to be parsed 159 | * @param complain if nonzero, report error messages via Clp_OptionError 160 | * @param user_data user data passed to Clp_AddType() 161 | * @return 1 if parsing succeeded, 0 otherwise 162 | */ 163 | typedef int (*Clp_ValParseFunc)(Clp_Parser *clp, const char *vstr, 164 | int complain, void *user_data); 165 | 166 | /** @brief A function for reporting option errors. 167 | * @param clp the parser 168 | * @param message error message 169 | */ 170 | typedef void (*Clp_ErrorHandler)(Clp_Parser *clp, const char *message); 171 | 172 | 173 | /** @brief Command line parser. 174 | * 175 | * A Clp_Parser object defines an instance of CLP, including allowed options, 176 | * value types, and current arguments. 177 | * @sa Clp_NewParser, Clp_SetOptions, Clp_SetArguments */ 178 | struct Clp_Parser { 179 | const Clp_Option *option; /**< The last option. */ 180 | 181 | int negated; /**< Whether the last option was negated. */ 182 | 183 | int have_val; /**< Whether the last option had a value. */ 184 | const char *vstr; /**< The string value provided with the last 185 | option. */ 186 | 187 | union { 188 | int i; 189 | unsigned u; 190 | long l; 191 | unsigned long ul; 192 | double d; 193 | const char *s; 194 | void *pv; 195 | #ifdef HAVE_INT64_TYPES 196 | int64_t i64; 197 | uint64_t u64; 198 | #endif 199 | char cs[Clp_ValSize]; 200 | unsigned char ucs[Clp_ValSize]; 201 | int is[Clp_ValIntSize]; 202 | unsigned us[Clp_ValIntSize]; 203 | } val; /**< The parsed value provided with the last 204 | option. */ 205 | 206 | void *user_data; /**< Uninterpreted by CLP; users can set 207 | arbitrarily. */ 208 | 209 | struct Clp_Internal *internal; 210 | }; 211 | 212 | /** @cond never */ 213 | #if __GNUC__ >= 4 214 | # define CLP_SENTINEL __attribute__((sentinel)) 215 | #else 216 | # define CLP_SENTINEL /* nothing */ 217 | #endif 218 | /** @endcond never */ 219 | 220 | 221 | /** @brief Create a new Clp_Parser. */ 222 | Clp_Parser *Clp_NewParser(int argc, const char * const *argv, 223 | int nopt, const Clp_Option *opt); 224 | 225 | /** @brief Destroy a Clp_Parser object. */ 226 | void Clp_DeleteParser(Clp_Parser *clp); 227 | 228 | 229 | /** @brief Return @a clp's program name. */ 230 | const char *Clp_ProgramName(Clp_Parser *clp); 231 | 232 | /** @brief Set @a clp's program name. */ 233 | const char *Clp_SetProgramName(Clp_Parser *clp, const char *name); 234 | 235 | 236 | /** @brief Set @a clp's error handler function. */ 237 | Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, Clp_ErrorHandler errh); 238 | 239 | /** @brief Set @a clp's UTF-8 mode. */ 240 | int Clp_SetUTF8(Clp_Parser *clp, int utf8); 241 | 242 | /** @brief Return @a clp's treatment of character @a c. */ 243 | int Clp_OptionChar(Clp_Parser *clp, int c); 244 | 245 | /** @brief Set @a clp's treatment of character @a c. */ 246 | int Clp_SetOptionChar(Clp_Parser *clp, int c, int type); 247 | 248 | /** @brief Set @a clp's option definitions. */ 249 | int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt); 250 | 251 | /** @brief Set @a clp's arguments. */ 252 | void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv); 253 | 254 | /** @brief Set whether @a clp is searching for options. */ 255 | int Clp_SetOptionProcessing(Clp_Parser *clp, int on); 256 | 257 | 258 | #define Clp_DisallowOptions (1<<0) /**< @brief Value type flag: value 259 | can't be an option string. 260 | 261 | See Clp_AddType(). */ 262 | 263 | /** @brief Define a new value type for @a clp. */ 264 | int Clp_AddType(Clp_Parser *clp, int val_type, int flags, 265 | Clp_ValParseFunc parser, void *user_data); 266 | 267 | 268 | #define Clp_AllowNumbers (1<<0) /**< @brief String list flag: allow 269 | explicit numbers. 270 | 271 | See Clp_AddStringListType() and Clp_AddStringListTypeVec(). */ 272 | #define Clp_StringListLong (1<<1) /**< @brief String list flag: values 273 | have long type. */ 274 | 275 | /** @brief Define a new string list value type for @a clp. */ 276 | int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, 277 | int nstrs, const char * const *strs, 278 | const int *vals); 279 | 280 | /** @brief Define a new string list value type for @a clp. */ 281 | int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) 282 | CLP_SENTINEL; 283 | 284 | 285 | /** @brief Parse and return the next argument from @a clp. */ 286 | int Clp_Next(Clp_Parser *clp); 287 | 288 | /** @brief Return the next argument from @a clp without option parsing. */ 289 | const char *Clp_Shift(Clp_Parser *clp, int allow_options); 290 | 291 | 292 | /** @brief Create a new Clp_ParserState. */ 293 | Clp_ParserState *Clp_NewParserState(void); 294 | 295 | /** @brief Destroy a Clp_ParserState object. */ 296 | void Clp_DeleteParserState(Clp_ParserState *state); 297 | 298 | /** @brief Save @a clp's current state in @a state. */ 299 | void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state); 300 | 301 | /** @brief Restore parser state from @a state into @a clp. */ 302 | void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state); 303 | 304 | 305 | /** @brief Report a parser error. */ 306 | int Clp_OptionError(Clp_Parser *clp, const char *format, ...); 307 | 308 | /** @brief Format a message. */ 309 | int Clp_vsnprintf(Clp_Parser* clp, char* str, size_t size, 310 | const char* format, va_list val); 311 | 312 | /** @brief Print a message. */ 313 | int Clp_fprintf(Clp_Parser* clp, FILE* f, const char* format, ...); 314 | 315 | /** @brief Print a message. */ 316 | int Clp_vfprintf(Clp_Parser* clp, FILE* f, const char* format, va_list val); 317 | 318 | /** @brief Extract the current option as a string. */ 319 | int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len); 320 | 321 | /** @brief Extract the current option as a string. */ 322 | const char *Clp_CurOptionName(Clp_Parser *clp); 323 | 324 | /** @brief Test if the current option had long name @a name. */ 325 | int Clp_IsLong(Clp_Parser *clp, const char *long_name); 326 | 327 | /** @brief Test if the current option had short name @a name. */ 328 | int Clp_IsShort(Clp_Parser *clp, int short_name); 329 | 330 | #undef CLP_SENTINEL 331 | #ifdef __cplusplus 332 | } 333 | #endif 334 | #endif 335 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/merge.c: -------------------------------------------------------------------------------- 1 | /* merge.c - Functions which actually combine and manipulate GIF image data. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of gifsicle. 4 | 5 | Gifsicle is free software. It is distributed under the GNU Public License, 6 | version 2; you can copy, distribute, or alter it at will, as long 7 | as this notice is kept intact and this source code is made available. There 8 | is no warranty, express or implied. */ 9 | 10 | #include 11 | #include "gifsicle.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | /* First merging stage: Mark the used colors in all colormaps. */ 20 | 21 | void 22 | unmark_colors(Gif_Colormap *gfcm) 23 | { 24 | int i; 25 | if (gfcm) 26 | for (i = 0; i < gfcm->ncol; i++) 27 | gfcm->col[i].haspixel = 0; 28 | } 29 | 30 | void 31 | unmark_colors_2(Gif_Colormap *gfcm) 32 | { 33 | int i; 34 | for (i = 0; i < gfcm->ncol; i++) { 35 | gfcm->col[i].pixel = 256; 36 | gfcm->col[i].haspixel = 0; 37 | } 38 | } 39 | 40 | 41 | void 42 | mark_used_colors(Gif_Stream *gfs, Gif_Image *gfi, Gt_Crop *crop, 43 | int compress_immediately) 44 | { 45 | Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; 46 | Gif_Color *col; 47 | int i, j, l, t, r, b, nleft, ncol, transp = gfi->transparent; 48 | 49 | /* There might not be a colormap. */ 50 | if (!gfcm) 51 | return; 52 | col = gfcm->col; 53 | ncol = gfcm->ncol; 54 | 55 | /* Mark color used for transparency. */ 56 | if (transp >= 0 && transp < ncol) 57 | col[transp].haspixel |= 2; 58 | 59 | /* Only mark colors until we've seen all of them. The left variable keeps 60 | track of how many are left. */ 61 | for (i = nleft = 0; i < ncol; ++i) 62 | if (!(col[i].haspixel & 1) && i != transp) 63 | ++nleft; 64 | if (nleft == 0) 65 | return; 66 | 67 | if (gfi->img || Gif_UncompressImage(gfs, gfi) == 2) 68 | compress_immediately = 0; 69 | 70 | /* Loop over every pixel (until we've seen all colors) */ 71 | if (crop) { 72 | Gt_Crop c; 73 | combine_crop(&c, crop, gfi); 74 | l = c.x; 75 | t = c.y; 76 | r = l + c.w; 77 | b = t + c.h; 78 | } else { 79 | l = t = 0; 80 | r = gfi->width; 81 | b = gfi->height; 82 | } 83 | 84 | for (j = t; j != b; ++j) { 85 | uint8_t *data = gfi->img[j] + l; 86 | for (i = l; i != r; ++i, ++data) 87 | if (*data < ncol && !(col[*data].haspixel & 1) && *data != transp) { 88 | col[*data].haspixel |= 1; 89 | --nleft; 90 | if (nleft == 0) 91 | goto done; 92 | } 93 | } 94 | 95 | done: 96 | if (compress_immediately > 0) 97 | Gif_ReleaseUncompressedImage(gfi); 98 | } 99 | 100 | 101 | int 102 | find_color_index(Gif_Color *c, int nc, Gif_Color *color) 103 | { 104 | int index; 105 | for (index = 0; index < nc; index++) 106 | if (GIF_COLOREQ(&c[index], color)) 107 | return index; 108 | return -1; 109 | } 110 | 111 | 112 | int 113 | merge_colormap_if_possible(Gif_Colormap *dest, Gif_Colormap *src) 114 | { 115 | Gif_Color *srccol; 116 | Gif_Color *destcol = dest->col; 117 | int ndestcol = dest->ncol; 118 | int dest_userflags = dest->userflags; 119 | int i, x; 120 | int trivial_map = 1; 121 | 122 | if (!src) 123 | return 1; 124 | 125 | srccol = src->col; 126 | for (i = 0; i < src->ncol; i++) { 127 | if (srccol[i].haspixel & 1) { 128 | /* Store an image color cell's mapping to the global colormap in 129 | its 'pixel' slot. This is useful caching: oftentimes many 130 | input frames will share a colormap */ 131 | int mapto = (srccol[i].pixel < 256 ? (int)srccol[i].pixel : -1); 132 | 133 | if (mapto == -1) 134 | mapto = find_color_index(destcol, ndestcol, &srccol[i]); 135 | 136 | if (mapto == -1 && ndestcol < 256) { 137 | /* add the color */ 138 | mapto = ndestcol; 139 | destcol[mapto] = srccol[i]; 140 | ndestcol++; 141 | } 142 | 143 | if (mapto == -1) 144 | /* check for a pure-transparent color */ 145 | for (x = 0; x < ndestcol; x++) 146 | if (destcol[x].haspixel == 2) { 147 | mapto = x; 148 | destcol[mapto] = srccol[i]; 149 | break; 150 | } 151 | 152 | if (mapto == -1) 153 | /* give up and require a local colormap */ 154 | goto local_colormap_required; 155 | 156 | assert(mapto >= 0 && mapto < ndestcol); 157 | assert(GIF_COLOREQ(&destcol[mapto], &srccol[i])); 158 | 159 | srccol[i].pixel = mapto; 160 | destcol[mapto].haspixel = 1; 161 | if (mapto != i) 162 | trivial_map = 0; 163 | 164 | } else if (srccol[i].haspixel & 2) { 165 | /* a dedicated transparent color; if trivial_map & at end of 166 | colormap insert it with haspixel == 2. (strictly not 167 | necessary; we do it to try to keep the map trivial.) */ 168 | if (trivial_map && i == ndestcol) { 169 | destcol[ndestcol] = srccol[i]; 170 | ndestcol++; 171 | } 172 | } 173 | } 174 | 175 | /* success! save new number of colors */ 176 | dest->ncol = ndestcol; 177 | dest->userflags = dest_userflags; 178 | return 1; 179 | 180 | /* failure: a local colormap is required */ 181 | local_colormap_required: 182 | if (warn_local_colormaps == 1) { 183 | static int context = 0; 184 | if (!context) { 185 | warning(1, "too many colors, using local colormaps\n" 186 | " (You may want to try %<--colors 256%>.)"); 187 | context = 1; 188 | } else 189 | warning(1, "too many colors, using local colormaps"); 190 | warn_local_colormaps = 2; 191 | } 192 | 193 | /* 9.Dec.1998 - This must have been a longstanding bug! We MUST clear 194 | the cached mappings of any pixels in the source colormap we 195 | assigned this time through, since we are throwing those colors 196 | away. We assigned it this time through if the cached mapping is >= 197 | dest->ncol. */ 198 | for (x = 0; x < i; x++) 199 | if ((srccol[x].haspixel & 1) && srccol[x].pixel >= (uint32_t)dest->ncol) 200 | srccol[x].pixel = 256; 201 | 202 | return 0; 203 | } 204 | 205 | 206 | void 207 | merge_stream(Gif_Stream *dest, Gif_Stream *src, int no_comments) 208 | { 209 | int i; 210 | assert(dest->global); 211 | 212 | /* unmark colors in global and local colormaps -- 12/9 */ 213 | if (src->global) 214 | unmark_colors_2(src->global); 215 | for (i = 0; i < src->nimages; i++) 216 | if (src->images[i]->local) 217 | unmark_colors_2(src->images[i]->local); 218 | 219 | if (dest->loopcount < 0) 220 | dest->loopcount = src->loopcount; 221 | 222 | if (src->end_comment && !no_comments) { 223 | if (!dest->end_comment) 224 | dest->end_comment = Gif_NewComment(); 225 | merge_comments(dest->end_comment, src->end_comment); 226 | } 227 | } 228 | 229 | 230 | void 231 | merge_comments(Gif_Comment *destc, Gif_Comment *srcc) 232 | { 233 | int i; 234 | for (i = 0; i < srcc->count; i++) 235 | Gif_AddComment(destc, srcc->str[i], srcc->len[i]); 236 | } 237 | 238 | 239 | static void merge_image_input_colors(uint8_t* inused, const Gif_Image* srci) { 240 | int i, x, y, nleft = Gif_ImageColorBound(srci); 241 | for (i = 0; i != 256; ++i) 242 | inused[i] = 0; 243 | for (y = 0; y != srci->height && nleft > 0; ++y) { 244 | const uint8_t* data = srci->img[y]; 245 | for (x = 0; x != srci->width; ++x, ++data) { 246 | nleft -= 1 - inused[*data]; 247 | inused[*data] = 1; 248 | } 249 | } 250 | if (srci->transparent >= 0) 251 | inused[srci->transparent] = 0; 252 | } 253 | 254 | 255 | Gif_Image * 256 | merge_image(Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci, 257 | Gt_Frame* srcfr, int same_compressed_ok) 258 | { 259 | Gif_Colormap *imagecm; 260 | int imagecm_ncol; 261 | int i; 262 | Gif_Colormap *localcm = 0; 263 | Gif_Colormap *destcm = dest->global; 264 | 265 | uint8_t map[256]; /* map[input pixel value] == output pixval */ 266 | int trivial_map; /* does the map take input pixval --> the same 267 | pixel value for all colors in the image? */ 268 | uint8_t inused[256]; /* inused[input pival] == 1 iff used */ 269 | uint8_t used[256]; /* used[output pixval K] == 1 iff K was used 270 | in the image */ 271 | 272 | 273 | Gif_Image *desti; 274 | 275 | /* mark colors that were actually used in this image */ 276 | imagecm = srci->local ? srci->local : src->global; 277 | imagecm_ncol = imagecm ? imagecm->ncol : 0; 278 | merge_image_input_colors(inused, srci); 279 | for (i = imagecm_ncol; i != 256; ++i) 280 | if (inused[i]) { 281 | lwarning(srcfr->input_filename, "some colors undefined by colormap"); 282 | break; 283 | } 284 | 285 | /* map[old_pixel_value] == new_pixel_value */ 286 | for (i = 0; i < 256; i++) 287 | map[i] = used[i] = 0; 288 | 289 | /* Merge the colormap */ 290 | if (merge_colormap_if_possible(dest->global, imagecm)) { 291 | /* Create 'map' and 'used' for global colormap. */ 292 | for (i = 0; i != imagecm_ncol; ++i) 293 | if (inused[i]) 294 | map[i] = imagecm->col[i].pixel; 295 | 296 | } else { 297 | /* Need a local colormap. */ 298 | destcm = localcm = Gif_NewFullColormap(0, 256); 299 | for (i = 0; i != imagecm_ncol; ++i) 300 | if (inused[i]) { 301 | map[i] = localcm->ncol; 302 | localcm->col[localcm->ncol] = imagecm->col[i]; 303 | ++localcm->ncol; 304 | } 305 | } 306 | 307 | trivial_map = 1; 308 | for (i = 0; i != 256; ++i) 309 | if (inused[i]) { 310 | used[map[i]] = 1; 311 | trivial_map = trivial_map && map[i] == i; 312 | } 313 | 314 | /* Decide on a transparent index */ 315 | if (srci->transparent >= 0) { 316 | int found_transparent = -1; 317 | 318 | /* try to keep the map trivial -- prefer same transparent index */ 319 | if (trivial_map && !used[srci->transparent]) 320 | found_transparent = srci->transparent; 321 | else 322 | for (i = destcm->ncol - 1; i >= 0; i--) 323 | if (!used[i]) 324 | found_transparent = i; 325 | 326 | /* 1.Aug.1999 - Allow for the case that the transparent index is bigger 327 | than the number of colors we've created thus far. */ 328 | if (found_transparent < 0 || found_transparent >= destcm->ncol) { 329 | Gif_Color *c; 330 | found_transparent = destcm->ncol; 331 | /* 1.Aug.1999 - Don't update destcm->ncol -- we want the output colormap 332 | to be as small as possible. */ 333 | c = &destcm->col[found_transparent]; 334 | if (imagecm && srci->transparent < imagecm->ncol) 335 | *c = imagecm->col[srci->transparent]; 336 | c->haspixel = 2; 337 | assert(c->haspixel == 2 && found_transparent < 256); 338 | } 339 | 340 | map[srci->transparent] = found_transparent; 341 | if (srci->transparent != found_transparent) trivial_map = 0; 342 | } 343 | 344 | assert(destcm->ncol <= 256); 345 | /* Make the new image. */ 346 | desti = Gif_NewImage(); 347 | 348 | desti->identifier = Gif_CopyString(srci->identifier); 349 | if (srci->transparent > -1) 350 | desti->transparent = map[srci->transparent]; 351 | desti->delay = srci->delay; 352 | desti->disposal = srci->disposal; 353 | desti->left = srci->left; 354 | desti->top = srci->top; 355 | desti->interlace = srci->interlace; 356 | 357 | desti->width = srci->width; 358 | desti->height = srci->height; 359 | desti->local = localcm; 360 | 361 | if (trivial_map && same_compressed_ok && srci->compressed) { 362 | desti->compressed_len = srci->compressed_len; 363 | desti->compressed = Gif_NewArray(uint8_t, srci->compressed_len); 364 | desti->free_compressed = Gif_Free; 365 | memcpy(desti->compressed, srci->compressed, srci->compressed_len); 366 | } else { 367 | int i, j; 368 | Gif_CreateUncompressedImage(desti, desti->interlace); 369 | 370 | if (trivial_map) 371 | for (j = 0; j < desti->height; j++) 372 | memcpy(desti->img[j], srci->img[j], desti->width); 373 | 374 | else 375 | for (j = 0; j < desti->height; j++) { 376 | uint8_t *srcdata = srci->img[j]; 377 | uint8_t *destdata = desti->img[j]; 378 | for (i = 0; i < desti->width; i++, srcdata++, destdata++) 379 | *destdata = map[*srcdata]; 380 | } 381 | } 382 | 383 | /* comments and extensions */ 384 | if (srci->comment) { 385 | desti->comment = Gif_NewComment(); 386 | merge_comments(desti->comment, srci->comment); 387 | } 388 | if (srci->extension_list && !srcfr->no_extensions) { 389 | Gif_Extension* gfex; 390 | for (gfex = srci->extension_list; gfex; gfex = gfex->next) 391 | if (gfex->kind != 255 || !srcfr->no_app_extensions) 392 | Gif_AddExtension(dest, desti, Gif_CopyExtension(gfex)); 393 | } 394 | while (srcfr->extensions) { 395 | Gif_Extension* next = srcfr->extensions->next; 396 | Gif_AddExtension(dest, desti, srcfr->extensions); 397 | srcfr->extensions = next; 398 | } 399 | 400 | Gif_AddImage(dest, desti); 401 | return desti; 402 | } 403 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/optimize.c: -------------------------------------------------------------------------------- 1 | /* optimize.c - Functions to optimize animated GIFs. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of gifsicle. 4 | 5 | Gifsicle is free software. It is distributed under the GNU Public License, 6 | version 2; you can copy, distribute, or alter it at will, as long 7 | as this notice is kept intact and this source code is made available. There 8 | is no warranty, express or implied. */ 9 | 10 | #include "config.h" 11 | #include "gifsicle.h" 12 | #include "kcolor.h" 13 | #include 14 | #include 15 | 16 | typedef int32_t penalty_type; 17 | 18 | typedef struct { 19 | int left; 20 | int top; 21 | int width; 22 | int height; 23 | } Gif_OptBounds; 24 | 25 | typedef struct { 26 | uint16_t left; 27 | uint16_t top; 28 | uint16_t width; 29 | uint16_t height; 30 | uint32_t size; 31 | uint8_t disposal; 32 | int transparent; 33 | uint8_t *needed_colors; 34 | unsigned required_color_count; 35 | int32_t active_penalty; 36 | int32_t global_penalty; 37 | int32_t colormap_penalty; 38 | Gif_Image *new_gfi; 39 | } Gif_OptData; 40 | 41 | /* Screen width and height */ 42 | static int screen_width; 43 | static int screen_height; 44 | 45 | /* Colormap containing all colors in the image. May have >256 colors */ 46 | static Gif_Colormap *all_colormap; 47 | /* Histogram so we can find colors quickly */ 48 | static kchist all_colormap_hist; 49 | 50 | /* The old global colormap, or a fake one we created if necessary */ 51 | static Gif_Colormap *in_global_map; 52 | 53 | /* The new global colormap */ 54 | static Gif_Colormap *out_global_map; 55 | 56 | #define TRANSP (0) 57 | #define NOT_IN_OUT_GLOBAL (256) 58 | static unsigned background; 59 | static int image_index; 60 | 61 | static penalty_type *permuting_sort_values; 62 | 63 | #define REQUIRED 2 64 | #define REPLACE_TRANSP 1 65 | 66 | 67 | /***** 68 | * SIMPLE HELPERS 69 | * new and delete optimize data; and colormap_combine; and sorting permutations 70 | **/ 71 | 72 | Gif_OptData * 73 | new_opt_data(void) 74 | { 75 | Gif_OptData *od = Gif_New(Gif_OptData); 76 | od->needed_colors = 0; 77 | od->global_penalty = 1; 78 | return od; 79 | } 80 | 81 | void 82 | delete_opt_data(Gif_OptData *od) 83 | { 84 | if (!od) return; 85 | Gif_DeleteArray(od->needed_colors); 86 | Gif_Delete(od); 87 | } 88 | 89 | 90 | /* all_colormap_add: Ensure that each color in 'src' is represented in 91 | 'all_colormap'. For each color 'i' in 'src', src->col[i].pixel == some j 92 | so that GIF_COLOREQ(&src->col[i], &all_colormap->col[j]). 93 | all_colormap->col[0] is reserved for transparency; no source color will 94 | be mapped to it. */ 95 | 96 | static void all_colormap_add(const Gif_Colormap* src) { 97 | int i; 98 | 99 | /* expand dst->col if necessary. This might change dst->col */ 100 | if (all_colormap->ncol + src->ncol >= all_colormap->capacity) { 101 | all_colormap->capacity *= 2; 102 | Gif_ReArray(all_colormap->col, Gif_Color, all_colormap->capacity); 103 | } 104 | 105 | for (i = 0; i < src->ncol; ++i) { 106 | kchistitem* khi = kchist_add(&all_colormap_hist, 107 | kc_makegfcng(&src->col[i]), 0); 108 | if (!khi->count) { 109 | all_colormap->col[all_colormap->ncol] = src->col[i]; 110 | all_colormap->col[all_colormap->ncol].pixel = 0; 111 | khi->count = all_colormap->ncol; 112 | ++all_colormap->ncol; 113 | } 114 | src->col[i].pixel = khi->count; 115 | } 116 | } 117 | 118 | 119 | /***** 120 | * MANIPULATING IMAGE AREAS 121 | **/ 122 | 123 | static Gif_OptBounds 124 | safe_bounds(Gif_Image *area) 125 | { 126 | /* Returns bounds constrained to lie within the screen. */ 127 | Gif_OptBounds b; 128 | b.left = constrain(0, area->left, screen_width); 129 | b.top = constrain(0, area->top, screen_height); 130 | b.width = constrain(0, area->left + area->width, screen_width) - b.left; 131 | b.height = constrain(0, area->top + area->height, screen_height) - b.top; 132 | return b; 133 | } 134 | 135 | 136 | /***** 137 | * FIND THE SMALLEST BOUNDING RECTANGLE ENCLOSING ALL CHANGES 138 | **/ 139 | 140 | /* fix_difference_bounds: make sure the image isn't 0x0. */ 141 | 142 | static void 143 | fix_difference_bounds(Gif_OptData *bounds) 144 | { 145 | if (bounds->width == 0 || bounds->height == 0) { 146 | bounds->top = 0; 147 | bounds->left = 0; 148 | bounds->width = 1; 149 | bounds->height = 1; 150 | } 151 | /* assert that image lies completely within screen */ 152 | assert(bounds->top < screen_height && bounds->left < screen_width 153 | && bounds->top + bounds->height <= screen_height 154 | && bounds->left + bounds->width <= screen_width); 155 | } 156 | 157 | 158 | /***** 159 | * CALCULATE OUTPUT GLOBAL COLORMAP 160 | **/ 161 | 162 | static void 163 | increment_penalties(Gif_OptData *opt, penalty_type *penalty, int32_t delta) 164 | { 165 | int i; 166 | int all_ncol = all_colormap->ncol; 167 | uint8_t *need = opt->needed_colors; 168 | for (i = 1; i < all_ncol; i++) 169 | if (need[i] == REQUIRED) 170 | penalty[i] += delta; 171 | } 172 | 173 | 174 | /***** 175 | * CREATE COLOR MAPPING FOR A PARTICULAR IMAGE 176 | **/ 177 | 178 | /* sort_colormap_permutation_rgb: for canonicalizing local colormaps by 179 | arranging them in RGB order */ 180 | 181 | static int 182 | colormap_rgb_permutation_sorter(const void *v1, const void *v2) 183 | { 184 | const Gif_Color *col1 = (const Gif_Color *)v1; 185 | const Gif_Color *col2 = (const Gif_Color *)v2; 186 | int value1 = (col1->gfc_red << 16) | (col1->gfc_green << 8) | col1->gfc_blue; 187 | int value2 = (col2->gfc_red << 16) | (col2->gfc_green << 8) | col2->gfc_blue; 188 | return value1 - value2; 189 | } 190 | 191 | 192 | /* prepare_colormap_map: Create and return an array of bytes mapping from 193 | global pixel values to pixel values for this image. It may add colormap 194 | cells to 'into'; if there isn't enough room in 'into', it will return 0. It 195 | sets the 'transparent' field of 'gfi->optdata', but otherwise doesn't 196 | change or read it at all. */ 197 | 198 | static uint8_t * 199 | prepare_colormap_map(Gif_Image *gfi, Gif_Colormap *into, uint8_t *need) 200 | { 201 | int i; 202 | int is_global = (into == out_global_map); 203 | 204 | int all_ncol = all_colormap->ncol; 205 | Gif_Color *all_col = all_colormap->col; 206 | 207 | int ncol = into->ncol; 208 | Gif_Color *col = into->col; 209 | 210 | uint8_t *map = Gif_NewArray(uint8_t, all_ncol); 211 | uint8_t into_used[256]; 212 | 213 | /* keep track of which pixel indices in 'into' have been used; initially, 214 | all unused */ 215 | for (i = 0; i < 256; i++) 216 | into_used[i] = 0; 217 | 218 | /* go over all non-transparent global pixels which MUST appear 219 | (need[P]==REQUIRED) and place them in 'into' */ 220 | for (i = 1; i < all_ncol; i++) { 221 | int val; 222 | if (need[i] != REQUIRED) 223 | continue; 224 | 225 | /* fail if a needed pixel isn't in the global map */ 226 | if (is_global) { 227 | val = all_col[i].pixel; 228 | if (val >= ncol) 229 | goto error; 230 | } else { 231 | /* always place colors in a local colormap */ 232 | if (ncol == 256) 233 | goto error; 234 | val = ncol; 235 | col[val] = all_col[i]; 236 | col[val].pixel = i; 237 | ncol++; 238 | } 239 | 240 | map[i] = val; 241 | into_used[val] = 1; 242 | } 243 | 244 | if (!is_global) { 245 | qsort(col, ncol, sizeof(Gif_Color), colormap_rgb_permutation_sorter); 246 | for (i = 0; i < ncol; ++i) 247 | map[col[i].pixel] = i; 248 | } 249 | 250 | /* now check for transparency */ 251 | gfi->transparent = -1; 252 | if (need[TRANSP]) { 253 | int transparent = -1; 254 | 255 | /* first, look for an unused index in 'into'. Pick the lowest one: the 256 | lower transparent index we get, the more likely we can shave a bit off 257 | min_code_bits later, thus saving space */ 258 | for (i = 0; i < ncol; i++) 259 | if (!into_used[i]) { 260 | transparent = i; 261 | break; 262 | } 263 | 264 | /* otherwise, [1.Aug.1999] use a fake slot for the purely transparent 265 | color. Don't actually enter the transparent color into the colormap -- 266 | we might be able to output a smaller colormap! If there's no room for 267 | it, give up */ 268 | if (transparent < 0) { 269 | if (ncol < 256) { 270 | transparent = ncol; 271 | /* 1.Aug.1999 - don't increase ncol */ 272 | col[ncol] = all_col[TRANSP]; 273 | } else 274 | goto error; 275 | } 276 | 277 | /* change mapping */ 278 | map[TRANSP] = transparent; 279 | for (i = 1; i < all_ncol; i++) 280 | if (need[i] == REPLACE_TRANSP) 281 | map[i] = transparent; 282 | 283 | gfi->transparent = transparent; 284 | } 285 | 286 | /* If we get here, it worked! Commit state changes (the number of color 287 | cells in 'into') and return the map. */ 288 | into->ncol = ncol; 289 | return map; 290 | 291 | error: 292 | /* If we get here, it failed! Return 0 and don't change global state. */ 293 | Gif_DeleteArray(map); 294 | return 0; 295 | } 296 | 297 | 298 | /* prepare_colormap: make a colormap up from the image data by fitting any 299 | used colors into a colormap. Returns a map from global color index to index 300 | in this image's colormap. May set a local colormap on 'gfi'. */ 301 | 302 | static uint8_t * 303 | prepare_colormap(Gif_Image *gfi, uint8_t *need) 304 | { 305 | uint8_t *map; 306 | 307 | /* try to map pixel values into the global colormap */ 308 | Gif_DeleteColormap(gfi->local); 309 | gfi->local = 0; 310 | map = prepare_colormap_map(gfi, out_global_map, need); 311 | 312 | if (!map) { 313 | /* that didn't work; add a local colormap. */ 314 | gfi->local = Gif_NewFullColormap(0, 256); 315 | map = prepare_colormap_map(gfi, gfi->local, need); 316 | } 317 | 318 | return map; 319 | } 320 | 321 | 322 | /***** 323 | * INITIALIZATION AND FINALIZATION 324 | **/ 325 | 326 | static int 327 | initialize_optimizer(Gif_Stream *gfs) 328 | { 329 | int i; 330 | 331 | if (gfs->nimages < 1) 332 | return 0; 333 | 334 | /* combine colormaps */ 335 | all_colormap = Gif_NewFullColormap(1, 384); 336 | all_colormap->col[0].gfc_red = 255; 337 | all_colormap->col[0].gfc_green = 255; 338 | all_colormap->col[0].gfc_blue = 255; 339 | 340 | in_global_map = gfs->global; 341 | if (!in_global_map) { 342 | Gif_Color *col; 343 | in_global_map = Gif_NewFullColormap(256, 256); 344 | col = in_global_map->col; 345 | for (i = 0; i < 256; i++, col++) 346 | col->gfc_red = col->gfc_green = col->gfc_blue = i; 347 | } 348 | 349 | { 350 | int any_globals = 0; 351 | int first_transparent = -1; 352 | 353 | kchist_init(&all_colormap_hist); 354 | for (i = 0; i < gfs->nimages; i++) { 355 | Gif_Image *gfi = gfs->images[i]; 356 | if (gfi->local) 357 | all_colormap_add(gfi->local); 358 | else 359 | any_globals = 1; 360 | if (gfi->transparent >= 0 && first_transparent < 0) 361 | first_transparent = i; 362 | } 363 | if (any_globals) 364 | all_colormap_add(in_global_map); 365 | kchist_cleanup(&all_colormap_hist); 366 | 367 | /* try and maintain transparency's pixel value */ 368 | if (first_transparent >= 0) { 369 | Gif_Image *gfi = gfs->images[first_transparent]; 370 | Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; 371 | all_colormap->col[TRANSP] = gfcm->col[gfi->transparent]; 372 | } 373 | } 374 | 375 | /* find screen_width and screen_height, and clip all images to screen */ 376 | Gif_CalculateScreenSize(gfs, 0); 377 | screen_width = gfs->screen_width; 378 | screen_height = gfs->screen_height; 379 | for (i = 0; i < gfs->nimages; i++) 380 | Gif_ClipImage(gfs->images[i], 0, 0, screen_width, screen_height); 381 | 382 | /* choose background */ 383 | if (gfs->images[0]->transparent < 0 384 | && gfs->global && gfs->background < in_global_map->ncol) 385 | background = in_global_map->col[gfs->background].pixel; 386 | else 387 | background = TRANSP; 388 | 389 | return 1; 390 | } 391 | 392 | static void 393 | finalize_optimizer(Gif_Stream *gfs, int optimize_flags) 394 | { 395 | int i; 396 | 397 | if (background == TRANSP) 398 | gfs->background = (uint8_t)gfs->images[0]->transparent; 399 | 400 | /* 11.Mar.2010 - remove entirely transparent frames. */ 401 | for (i = 1; i < gfs->nimages && !(optimize_flags & GT_OPT_KEEPEMPTY); ++i) { 402 | Gif_Image *gfi = gfs->images[i]; 403 | if (gfi->width == 1 && gfi->height == 1 && gfi->transparent >= 0 404 | && !gfi->identifier && !gfi->comment 405 | && (gfi->disposal == GIF_DISPOSAL_ASIS 406 | || gfi->disposal == GIF_DISPOSAL_NONE 407 | || gfi->disposal == GIF_DISPOSAL_PREVIOUS) 408 | && gfi->delay && gfs->images[i-1]->delay) { 409 | Gif_UncompressImage(gfs, gfi); 410 | if (gfi->img[0][0] == gfi->transparent 411 | && (gfs->images[i-1]->disposal == GIF_DISPOSAL_ASIS 412 | || gfs->images[i-1]->disposal == GIF_DISPOSAL_NONE)) { 413 | gfs->images[i-1]->delay += gfi->delay; 414 | Gif_DeleteImage(gfi); 415 | memmove(&gfs->images[i], &gfs->images[i+1], sizeof(Gif_Image *) * (gfs->nimages - i - 1)); 416 | --gfs->nimages; 417 | --i; 418 | } 419 | } 420 | } 421 | 422 | /* 10.Dec.1998 - prefer GIF_DISPOSAL_NONE to GIF_DISPOSAL_ASIS. This is 423 | semantically "wrong" -- it's better to set the disposal explicitly than 424 | rely on default behavior -- but will result in smaller GIF files, since 425 | the graphic control extension can be left off in many cases. */ 426 | for (i = 0; i < gfs->nimages; i++) 427 | if (gfs->images[i]->disposal == GIF_DISPOSAL_ASIS 428 | && gfs->images[i]->delay == 0 429 | && gfs->images[i]->transparent < 0) 430 | gfs->images[i]->disposal = GIF_DISPOSAL_NONE; 431 | 432 | Gif_DeleteColormap(in_global_map); 433 | Gif_DeleteColormap(all_colormap); 434 | } 435 | 436 | 437 | /* two versions of the optimization template */ 438 | #define palindex_type uint16_t 439 | #define X(t) t ## 16 440 | #include "opttemplate.c" 441 | #undef palindex_type 442 | #undef X 443 | 444 | #define palindex_type uint32_t 445 | #define X(t) t ## 32 446 | #include "opttemplate.c" 447 | 448 | /* the interface function! */ 449 | 450 | void 451 | optimize_fragments(Gif_Stream *gfs, int optimize_flags, int huge_stream) 452 | { 453 | if (!initialize_optimizer(gfs)) 454 | return; 455 | if ((unsigned) all_colormap->ncol >= 0xFFFF) { 456 | create_subimages32(gfs, optimize_flags, !huge_stream); 457 | create_out_global_map32(gfs); 458 | create_new_image_data32(gfs, optimize_flags); 459 | finalize_optimizer_data32(); 460 | } else { 461 | create_subimages16(gfs, optimize_flags, !huge_stream); 462 | create_out_global_map16(gfs); 463 | create_new_image_data16(gfs, optimize_flags); 464 | finalize_optimizer_data16(); 465 | } 466 | finalize_optimizer(gfs, optimize_flags); 467 | } 468 | 469 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/giffunc.c: -------------------------------------------------------------------------------- 1 | /* giffunc.c - General functions for the GIF library. 2 | Copyright (C) 1997-2014 Eddie Kohler, ekohler@gmail.com 3 | This file is part of the LCDF GIF library. 4 | 5 | The LCDF GIF library is free software. It is distributed under the GNU 6 | General Public License, version 2; you can copy, distribute, or alter it at 7 | will, as long as this notice is kept intact and this source code is made 8 | available. There is no warranty, express or implied. */ 9 | 10 | #if HAVE_CONFIG_H 11 | # include 12 | #endif 13 | #include "gif.h" 14 | #include 15 | #include 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | Gif_Stream * 22 | Gif_NewStream(void) 23 | { 24 | Gif_Stream *gfs = Gif_New(Gif_Stream); 25 | if (!gfs) 26 | return 0; 27 | gfs->images = 0; 28 | gfs->nimages = gfs->imagescap = 0; 29 | gfs->global = 0; 30 | gfs->background = 256; 31 | gfs->screen_width = gfs->screen_height = 0; 32 | gfs->loopcount = -1; 33 | gfs->end_comment = 0; 34 | gfs->end_extension_list = 0; 35 | gfs->errors = 0; 36 | gfs->userflags = 0; 37 | gfs->refcount = 0; 38 | gfs->landmark = 0; 39 | return gfs; 40 | } 41 | 42 | 43 | Gif_Image * 44 | Gif_NewImage(void) 45 | { 46 | Gif_Image *gfi = Gif_New(Gif_Image); 47 | if (!gfi) 48 | return 0; 49 | gfi->width = gfi->height = 0; 50 | gfi->img = 0; 51 | gfi->image_data = 0; 52 | gfi->left = gfi->top = 0; 53 | gfi->delay = 0; 54 | gfi->disposal = GIF_DISPOSAL_NONE; 55 | gfi->interlace = 0; 56 | gfi->local = 0; 57 | gfi->transparent = -1; 58 | gfi->user_flags = 0; 59 | gfi->identifier = 0; 60 | gfi->comment = 0; 61 | gfi->extension_list = 0; 62 | gfi->free_image_data = Gif_Free; 63 | gfi->compressed_len = 0; 64 | gfi->compressed = 0; 65 | gfi->free_compressed = 0; 66 | gfi->user_data = 0; 67 | gfi->free_user_data = 0; 68 | gfi->refcount = 0; 69 | return gfi; 70 | } 71 | 72 | 73 | Gif_Colormap * 74 | Gif_NewColormap(void) 75 | { 76 | Gif_Colormap *gfcm = Gif_New(Gif_Colormap); 77 | if (!gfcm) 78 | return 0; 79 | gfcm->ncol = 0; 80 | gfcm->capacity = 0; 81 | gfcm->col = 0; 82 | gfcm->refcount = 0; 83 | gfcm->userflags = 0; 84 | return gfcm; 85 | } 86 | 87 | 88 | Gif_Colormap * 89 | Gif_NewFullColormap(int count, int capacity) 90 | { 91 | Gif_Colormap *gfcm = Gif_New(Gif_Colormap); 92 | if (!gfcm || capacity <= 0 || count < 0) { 93 | Gif_Delete(gfcm); 94 | return 0; 95 | } 96 | if (count > capacity) 97 | capacity = count; 98 | gfcm->ncol = count; 99 | gfcm->capacity = capacity; 100 | gfcm->col = Gif_NewArray(Gif_Color, capacity); 101 | gfcm->refcount = 0; 102 | gfcm->userflags = 0; 103 | if (!gfcm->col) { 104 | Gif_Delete(gfcm); 105 | return 0; 106 | } else 107 | return gfcm; 108 | } 109 | 110 | 111 | Gif_Comment * 112 | Gif_NewComment(void) 113 | { 114 | Gif_Comment *gfcom = Gif_New(Gif_Comment); 115 | if (!gfcom) 116 | return 0; 117 | gfcom->str = 0; 118 | gfcom->len = 0; 119 | gfcom->count = gfcom->cap = 0; 120 | return gfcom; 121 | } 122 | 123 | 124 | Gif_Extension * 125 | Gif_NewExtension(int kind, const char* appname, int applength) 126 | { 127 | Gif_Extension *gfex = Gif_New(Gif_Extension); 128 | if (!gfex) 129 | return 0; 130 | gfex->kind = kind; 131 | if (appname) { 132 | gfex->appname = (char*) Gif_NewArray(char, applength + 1); 133 | if (!gfex->appname) { 134 | Gif_Delete(gfex); 135 | return 0; 136 | } 137 | memcpy(gfex->appname, appname, applength); 138 | gfex->appname[applength] = 0; 139 | gfex->applength = applength; 140 | } else { 141 | gfex->appname = 0; 142 | gfex->applength = 0; 143 | } 144 | gfex->data = 0; 145 | gfex->stream = 0; 146 | gfex->image = 0; 147 | gfex->next = 0; 148 | gfex->free_data = 0; 149 | gfex->packetized = 0; 150 | return gfex; 151 | } 152 | 153 | Gif_Extension* 154 | Gif_CopyExtension(Gif_Extension* src) 155 | { 156 | Gif_Extension* dst = Gif_NewExtension(src->kind, src->appname, src->applength); 157 | if (!dst) 158 | return NULL; 159 | if (!src->data || !src->free_data) { 160 | dst->data = src->data; 161 | dst->length = src->length; 162 | } else { 163 | dst->data = Gif_NewArray(uint8_t, src->length); 164 | if (!dst->data) { 165 | Gif_DeleteExtension(dst); 166 | return NULL; 167 | } 168 | memcpy(dst->data, src->data, src->length); 169 | dst->length = src->length; 170 | dst->free_data = Gif_Free; 171 | } 172 | dst->packetized = src->packetized; 173 | return dst; 174 | } 175 | 176 | 177 | char * 178 | Gif_CopyString(const char *s) 179 | { 180 | int l; 181 | char *copy; 182 | if (!s) 183 | return 0; 184 | l = strlen(s); 185 | copy = Gif_NewArray(char, l + 1); 186 | if (!copy) 187 | return 0; 188 | memcpy(copy, s, l + 1); 189 | return copy; 190 | } 191 | 192 | 193 | int 194 | Gif_AddImage(Gif_Stream *gfs, Gif_Image *gfi) 195 | { 196 | if (gfs->nimages >= gfs->imagescap) { 197 | if (gfs->imagescap) 198 | gfs->imagescap *= 2; 199 | else 200 | gfs->imagescap = 2; 201 | Gif_ReArray(gfs->images, Gif_Image *, gfs->imagescap); 202 | if (!gfs->images) 203 | return 0; 204 | } 205 | gfs->images[gfs->nimages] = gfi; 206 | gfs->nimages++; 207 | gfi->refcount++; 208 | return 1; 209 | } 210 | 211 | 212 | void 213 | Gif_RemoveImage(Gif_Stream *gfs, int inum) 214 | { 215 | int j; 216 | if (inum < 0 || inum >= gfs->nimages) 217 | return; 218 | Gif_DeleteImage(gfs->images[inum]); 219 | for (j = inum; j < gfs->nimages - 1; j++) 220 | gfs->images[j] = gfs->images[j+1]; 221 | gfs->nimages--; 222 | } 223 | 224 | 225 | int 226 | Gif_ImageColorBound(const Gif_Image* gfi) 227 | { 228 | if (gfi->compressed) 229 | return 1 << gfi->compressed[0]; 230 | else 231 | return 256; 232 | } 233 | 234 | 235 | int 236 | Gif_AddCommentTake(Gif_Comment *gfcom, char *x, int xlen) 237 | { 238 | if (gfcom->count >= gfcom->cap) { 239 | if (gfcom->cap) 240 | gfcom->cap *= 2; 241 | else 242 | gfcom->cap = 2; 243 | Gif_ReArray(gfcom->str, char *, gfcom->cap); 244 | Gif_ReArray(gfcom->len, int, gfcom->cap); 245 | if (!gfcom->str || !gfcom->len) 246 | return 0; 247 | } 248 | if (xlen < 0) 249 | xlen = strlen(x); 250 | gfcom->str[ gfcom->count ] = x; 251 | gfcom->len[ gfcom->count ] = xlen; 252 | gfcom->count++; 253 | return 1; 254 | } 255 | 256 | 257 | int 258 | Gif_AddComment(Gif_Comment *gfcom, const char *x, int xlen) 259 | { 260 | char *new_x; 261 | if (xlen < 0) 262 | xlen = strlen(x); 263 | new_x = Gif_NewArray(char, xlen); 264 | if (!new_x) 265 | return 0; 266 | memcpy(new_x, x, xlen); 267 | if (Gif_AddCommentTake(gfcom, new_x, xlen) == 0) { 268 | Gif_DeleteArray(new_x); 269 | return 0; 270 | } else 271 | return 1; 272 | } 273 | 274 | 275 | int 276 | Gif_AddExtension(Gif_Stream* gfs, Gif_Image* gfi, Gif_Extension* gfex) 277 | { 278 | Gif_Extension **pprev; 279 | if (gfex->stream || gfex->image) 280 | return 0; 281 | pprev = gfi ? &gfi->extension_list : &gfs->end_extension_list; 282 | while (*pprev) 283 | pprev = &(*pprev)->next; 284 | *pprev = gfex; 285 | gfex->stream = gfs; 286 | gfex->image = gfi; 287 | gfex->next = 0; 288 | return 1; 289 | } 290 | 291 | 292 | int 293 | Gif_ImageNumber(Gif_Stream *gfs, Gif_Image *gfi) 294 | { 295 | int i; 296 | if (gfs && gfi) 297 | for (i = 0; i != gfs->nimages; ++i) 298 | if (gfs->images[i] == gfi) 299 | return i; 300 | return -1; 301 | } 302 | 303 | 304 | void 305 | Gif_CalculateScreenSize(Gif_Stream *gfs, int force) 306 | { 307 | int i; 308 | int screen_width = 0; 309 | int screen_height = 0; 310 | 311 | for (i = 0; i < gfs->nimages; i++) { 312 | Gif_Image *gfi = gfs->images[i]; 313 | /* 17.Dec.1999 - I find this old behavior annoying. */ 314 | /* if (gfi->left != 0 || gfi->top != 0) continue; */ 315 | if (screen_width < gfi->left + gfi->width) 316 | screen_width = gfi->left + gfi->width; 317 | if (screen_height < gfi->top + gfi->height) 318 | screen_height = gfi->top + gfi->height; 319 | } 320 | 321 | /* Only use the default 640x480 screen size if we are being forced to create 322 | a new screen size or there's no screen size currently. */ 323 | if (screen_width == 0 && (gfs->screen_width == 0 || force)) 324 | screen_width = 640; 325 | if (screen_height == 0 && (gfs->screen_height == 0 || force)) 326 | screen_height = 480; 327 | 328 | if (gfs->screen_width < screen_width || force) 329 | gfs->screen_width = screen_width; 330 | if (gfs->screen_height < screen_height || force) 331 | gfs->screen_height = screen_height; 332 | } 333 | 334 | 335 | Gif_Stream * 336 | Gif_CopyStreamSkeleton(Gif_Stream *gfs) 337 | { 338 | Gif_Stream *ngfs = Gif_NewStream(); 339 | if (!ngfs) 340 | return 0; 341 | ngfs->global = Gif_CopyColormap(gfs->global); 342 | ngfs->background = gfs->background; 343 | ngfs->screen_width = gfs->screen_width; 344 | ngfs->screen_height = gfs->screen_height; 345 | ngfs->loopcount = gfs->loopcount; 346 | if (gfs->global && !ngfs->global) { 347 | Gif_DeleteStream(ngfs); 348 | return 0; 349 | } else 350 | return ngfs; 351 | } 352 | 353 | 354 | Gif_Stream * 355 | Gif_CopyStreamImages(Gif_Stream *gfs) 356 | { 357 | Gif_Stream *ngfs = Gif_CopyStreamSkeleton(gfs); 358 | int i; 359 | if (!ngfs) 360 | return 0; 361 | for (i = 0; i < gfs->nimages; i++) { 362 | Gif_Image *gfi = Gif_CopyImage(gfs->images[i]); 363 | if (!gfi || !Gif_AddImage(ngfs, gfi)) { 364 | Gif_DeleteStream(ngfs); 365 | return 0; 366 | } 367 | } 368 | return ngfs; 369 | } 370 | 371 | 372 | Gif_Colormap * 373 | Gif_CopyColormap(Gif_Colormap *src) 374 | { 375 | Gif_Colormap *dest; 376 | if (!src) 377 | return 0; 378 | 379 | dest = Gif_NewFullColormap(src->ncol, src->capacity); 380 | if (!dest) 381 | return 0; 382 | 383 | memcpy(dest->col, src->col, sizeof(src->col[0]) * src->ncol); 384 | return dest; 385 | } 386 | 387 | 388 | Gif_Image * 389 | Gif_CopyImage(Gif_Image *src) 390 | { 391 | Gif_Image *dest; 392 | uint8_t *data; 393 | int i; 394 | if (!src) 395 | return 0; 396 | 397 | dest = Gif_NewImage(); 398 | if (!dest) 399 | return 0; 400 | 401 | dest->identifier = Gif_CopyString(src->identifier); 402 | if (!dest->identifier && src->identifier) 403 | goto failure; 404 | if (src->comment) { 405 | dest->comment = Gif_NewComment(); 406 | if (!dest->comment) 407 | goto failure; 408 | for (i = 0; i < src->comment->count; i++) 409 | if (!Gif_AddComment(dest->comment, src->comment->str[i], 410 | src->comment->len[i])) 411 | goto failure; 412 | } 413 | if (src->extension_list) { 414 | Gif_Extension* gfex = src->extension_list; 415 | while (gfex) { 416 | Gif_Extension* dstex = Gif_CopyExtension(gfex); 417 | if (!dstex) 418 | goto failure; 419 | Gif_AddExtension(NULL, dest, dstex); 420 | gfex = gfex->next; 421 | } 422 | } 423 | 424 | dest->local = Gif_CopyColormap(src->local); 425 | if (!dest->local && src->local) 426 | goto failure; 427 | dest->transparent = src->transparent; 428 | 429 | dest->delay = src->delay; 430 | dest->disposal = src->disposal; 431 | dest->left = src->left; 432 | dest->top = src->top; 433 | 434 | dest->width = src->width; 435 | dest->height = src->height; 436 | 437 | dest->interlace = src->interlace; 438 | if (src->img) { 439 | dest->img = Gif_NewArray(uint8_t *, dest->height + 1); 440 | dest->image_data = Gif_NewArray(uint8_t, (size_t) dest->width * (size_t) dest->height); 441 | dest->free_image_data = Gif_Free; 442 | if (!dest->img || !dest->image_data) 443 | goto failure; 444 | for (i = 0, data = dest->image_data; i < dest->height; i++) { 445 | memcpy(data, src->img[i], dest->width); 446 | dest->img[i] = data; 447 | data += dest->width; 448 | } 449 | dest->img[dest->height] = 0; 450 | } 451 | if (src->compressed) { 452 | if (src->free_compressed == 0) 453 | dest->compressed = src->compressed; 454 | else { 455 | dest->compressed = Gif_NewArray(uint8_t, src->compressed_len); 456 | dest->free_compressed = Gif_Free; 457 | memcpy(dest->compressed, src->compressed, src->compressed_len); 458 | } 459 | dest->compressed_len = src->compressed_len; 460 | } 461 | 462 | return dest; 463 | 464 | failure: 465 | Gif_DeleteImage(dest); 466 | return 0; 467 | } 468 | 469 | 470 | void Gif_MakeImageEmpty(Gif_Image* gfi) { 471 | Gif_ReleaseUncompressedImage(gfi); 472 | Gif_ReleaseCompressedImage(gfi); 473 | gfi->width = gfi->height = 1; 474 | gfi->transparent = 0; 475 | Gif_CreateUncompressedImage(gfi, 0); 476 | gfi->img[0][0] = 0; 477 | } 478 | 479 | 480 | /** DELETION **/ 481 | 482 | typedef struct Gif_DeletionHook { 483 | int kind; 484 | Gif_DeletionHookFunc func; 485 | void *callback_data; 486 | struct Gif_DeletionHook *next; 487 | } Gif_DeletionHook; 488 | 489 | static Gif_DeletionHook *all_hooks; 490 | 491 | void 492 | Gif_DeleteStream(Gif_Stream *gfs) 493 | { 494 | Gif_DeletionHook *hook; 495 | int i; 496 | if (!gfs || --gfs->refcount > 0) 497 | return; 498 | 499 | for (i = 0; i < gfs->nimages; i++) 500 | Gif_DeleteImage(gfs->images[i]); 501 | Gif_DeleteArray(gfs->images); 502 | 503 | Gif_DeleteColormap(gfs->global); 504 | 505 | Gif_DeleteComment(gfs->end_comment); 506 | while (gfs->end_extension_list) 507 | Gif_DeleteExtension(gfs->end_extension_list); 508 | 509 | for (hook = all_hooks; hook; hook = hook->next) 510 | if (hook->kind == GIF_T_STREAM) 511 | (*hook->func)(GIF_T_STREAM, gfs, hook->callback_data); 512 | Gif_Delete(gfs); 513 | } 514 | 515 | 516 | void 517 | Gif_DeleteImage(Gif_Image *gfi) 518 | { 519 | Gif_DeletionHook *hook; 520 | if (!gfi || --gfi->refcount > 0) 521 | return; 522 | 523 | for (hook = all_hooks; hook; hook = hook->next) 524 | if (hook->kind == GIF_T_IMAGE) 525 | (*hook->func)(GIF_T_IMAGE, gfi, hook->callback_data); 526 | 527 | Gif_DeleteArray(gfi->identifier); 528 | Gif_DeleteComment(gfi->comment); 529 | while (gfi->extension_list) 530 | Gif_DeleteExtension(gfi->extension_list); 531 | Gif_DeleteColormap(gfi->local); 532 | if (gfi->image_data && gfi->free_image_data) 533 | (*gfi->free_image_data)((void *)gfi->image_data); 534 | Gif_DeleteArray(gfi->img); 535 | if (gfi->compressed && gfi->free_compressed) 536 | (*gfi->free_compressed)((void *)gfi->compressed); 537 | if (gfi->user_data && gfi->free_user_data) 538 | (*gfi->free_user_data)(gfi->user_data); 539 | Gif_Delete(gfi); 540 | } 541 | 542 | 543 | void 544 | Gif_DeleteColormap(Gif_Colormap *gfcm) 545 | { 546 | Gif_DeletionHook *hook; 547 | if (!gfcm || --gfcm->refcount > 0) 548 | return; 549 | 550 | for (hook = all_hooks; hook; hook = hook->next) 551 | if (hook->kind == GIF_T_COLORMAP) 552 | (*hook->func)(GIF_T_COLORMAP, gfcm, hook->callback_data); 553 | 554 | Gif_DeleteArray(gfcm->col); 555 | Gif_Delete(gfcm); 556 | } 557 | 558 | 559 | void 560 | Gif_DeleteComment(Gif_Comment *gfcom) 561 | { 562 | int i; 563 | if (!gfcom) 564 | return; 565 | for (i = 0; i < gfcom->count; i++) 566 | Gif_DeleteArray(gfcom->str[i]); 567 | Gif_DeleteArray(gfcom->str); 568 | Gif_DeleteArray(gfcom->len); 569 | Gif_Delete(gfcom); 570 | } 571 | 572 | 573 | void 574 | Gif_DeleteExtension(Gif_Extension *gfex) 575 | { 576 | if (!gfex) 577 | return; 578 | if (gfex->data && gfex->free_data) 579 | (*gfex->free_data)(gfex->data); 580 | Gif_DeleteArray(gfex->appname); 581 | if (gfex->stream || gfex->image) { 582 | Gif_Extension** pprev; 583 | if (gfex->image) 584 | pprev = &gfex->image->extension_list; 585 | else 586 | pprev = &gfex->stream->end_extension_list; 587 | while (*pprev && *pprev != gfex) 588 | pprev = &(*pprev)->next; 589 | if (*pprev) 590 | *pprev = gfex->next; 591 | } 592 | Gif_Delete(gfex); 593 | } 594 | 595 | 596 | /** DELETION HOOKS **/ 597 | 598 | int 599 | Gif_AddDeletionHook(int kind, void (*func)(int, void *, void *), void *cb) 600 | { 601 | Gif_DeletionHook *hook = Gif_New(Gif_DeletionHook); 602 | if (!hook) 603 | return 0; 604 | Gif_RemoveDeletionHook(kind, func, cb); 605 | hook->kind = kind; 606 | hook->func = func; 607 | hook->callback_data = cb; 608 | hook->next = all_hooks; 609 | all_hooks = hook; 610 | return 1; 611 | } 612 | 613 | void 614 | Gif_RemoveDeletionHook(int kind, void (*func)(int, void *, void *), void *cb) 615 | { 616 | Gif_DeletionHook *hook = all_hooks, *prev = 0; 617 | while (hook) { 618 | if (hook->kind == kind && hook->func == func 619 | && hook->callback_data == cb) { 620 | if (prev) 621 | prev->next = hook->next; 622 | else 623 | all_hooks = hook->next; 624 | Gif_Delete(hook); 625 | return; 626 | } 627 | prev = hook; 628 | hook = hook->next; 629 | } 630 | } 631 | 632 | 633 | int 634 | Gif_ColorEq(Gif_Color *c1, Gif_Color *c2) 635 | { 636 | return GIF_COLOREQ(c1, c2); 637 | } 638 | 639 | 640 | int 641 | Gif_FindColor(Gif_Colormap *gfcm, Gif_Color *c) 642 | { 643 | int i; 644 | for (i = 0; i < gfcm->ncol; i++) 645 | if (GIF_COLOREQ(&gfcm->col[i], c)) 646 | return i; 647 | return -1; 648 | } 649 | 650 | 651 | int 652 | Gif_AddColor(Gif_Colormap *gfcm, Gif_Color *c, int look_from) 653 | { 654 | int i; 655 | if (look_from >= 0) 656 | for (i = look_from; i < gfcm->ncol; i++) 657 | if (GIF_COLOREQ(&gfcm->col[i], c)) 658 | return i; 659 | if (gfcm->ncol >= gfcm->capacity) { 660 | gfcm->capacity *= 2; 661 | Gif_ReArray(gfcm->col, Gif_Color, gfcm->capacity); 662 | if (gfcm->col == 0) 663 | return -1; 664 | } 665 | i = gfcm->ncol; 666 | gfcm->ncol++; 667 | gfcm->col[i] = *c; 668 | return i; 669 | } 670 | 671 | 672 | Gif_Image * 673 | Gif_GetImage(Gif_Stream *gfs, int imagenumber) 674 | { 675 | if (imagenumber >= 0 && imagenumber < gfs->nimages) 676 | return gfs->images[imagenumber]; 677 | else 678 | return 0; 679 | } 680 | 681 | 682 | Gif_Image * 683 | Gif_GetNamedImage(Gif_Stream *gfs, const char *name) 684 | { 685 | int i; 686 | 687 | if (!name) 688 | return gfs->nimages ? gfs->images[0] : 0; 689 | 690 | for (i = 0; i < gfs->nimages; i++) 691 | if (gfs->images[i]->identifier && 692 | strcmp(gfs->images[i]->identifier, name) == 0) 693 | return gfs->images[i]; 694 | 695 | return 0; 696 | } 697 | 698 | 699 | void 700 | Gif_ReleaseCompressedImage(Gif_Image *gfi) 701 | { 702 | if (gfi->compressed && gfi->free_compressed) 703 | (*gfi->free_compressed)(gfi->compressed); 704 | gfi->compressed = 0; 705 | gfi->compressed_len = 0; 706 | gfi->free_compressed = 0; 707 | } 708 | 709 | void 710 | Gif_ReleaseUncompressedImage(Gif_Image *gfi) 711 | { 712 | Gif_DeleteArray(gfi->img); 713 | if (gfi->image_data && gfi->free_image_data) 714 | (*gfi->free_image_data)(gfi->image_data); 715 | gfi->img = 0; 716 | gfi->image_data = 0; 717 | gfi->free_image_data = 0; 718 | } 719 | 720 | 721 | int 722 | Gif_ClipImage(Gif_Image *gfi, int left, int top, int width, int height) 723 | { 724 | int new_width = gfi->width, new_height = gfi->height; 725 | int y; 726 | 727 | if (!gfi->img) 728 | return 0; 729 | 730 | if (gfi->left < left) { 731 | int shift = left - gfi->left; 732 | for (y = 0; y < gfi->height; y++) 733 | gfi->img[y] += shift; 734 | gfi->left += shift; 735 | new_width -= shift; 736 | } 737 | 738 | if (gfi->top < top) { 739 | int shift = top - gfi->top; 740 | for (y = gfi->height - 1; y >= shift; y++) 741 | gfi->img[y - shift] = gfi->img[y]; 742 | gfi->top += shift; 743 | new_height -= shift; 744 | } 745 | 746 | if (gfi->left + new_width >= width) 747 | new_width = width - gfi->left; 748 | 749 | if (gfi->top + new_height >= height) 750 | new_height = height - gfi->top; 751 | 752 | if (new_width < 0) 753 | new_width = 0; 754 | if (new_height < 0) 755 | new_height = 0; 756 | gfi->width = new_width; 757 | gfi->height = new_height; 758 | return 1; 759 | } 760 | 761 | 762 | int 763 | Gif_InterlaceLine(int line, int height) 764 | { 765 | height--; 766 | if (line > height / 2) 767 | return line * 2 - ( height | 1); 768 | else if (line > height / 4) 769 | return line * 4 - ((height & ~1) | 2); 770 | else if (line > height / 8) 771 | return line * 8 - ((height & ~3) | 4); 772 | else 773 | return line * 8; 774 | } 775 | 776 | 777 | int 778 | Gif_SetUncompressedImage(Gif_Image *gfi, uint8_t *image_data, 779 | void (*free_data)(void *), int data_interlaced) 780 | { 781 | /* NB does not affect compressed image (and must not) */ 782 | unsigned i; 783 | unsigned width = gfi->width; 784 | unsigned height = gfi->height; 785 | uint8_t **img; 786 | 787 | Gif_ReleaseUncompressedImage(gfi); 788 | if (!image_data) 789 | return 0; 790 | 791 | img = Gif_NewArray(uint8_t *, height + 1); 792 | if (!img) 793 | return 0; 794 | 795 | if (data_interlaced) 796 | for (i = 0; i < height; i++) 797 | img[ Gif_InterlaceLine(i, height) ] = image_data + width * i; 798 | else 799 | for (i = 0; i < height; i++) 800 | img[i] = image_data + width * i; 801 | img[height] = 0; 802 | 803 | gfi->img = img; 804 | gfi->image_data = image_data; 805 | gfi->free_image_data = free_data; 806 | return 1; 807 | } 808 | 809 | int 810 | Gif_CreateUncompressedImage(Gif_Image *gfi, int data_interlaced) 811 | { 812 | size_t sz = (size_t) gfi->width * (size_t) gfi->height; 813 | uint8_t *data = Gif_NewArray(uint8_t, sz ? sz : 1); 814 | return Gif_SetUncompressedImage(gfi, data, Gif_Free, data_interlaced); 815 | } 816 | 817 | void 818 | Gif_InitCompressInfo(Gif_CompressInfo *gcinfo) 819 | { 820 | gcinfo->flags = 0; 821 | gcinfo->loss = 0; 822 | } 823 | 824 | 825 | void 826 | Gif_Debug(char *x, ...) 827 | { 828 | va_list val; 829 | va_start(val, x); 830 | vfprintf(stderr, x, val); 831 | va_end(val); 832 | } 833 | 834 | 835 | #if !GIF_ALLOCATOR_DEFINED 836 | void* Gif_Realloc(void* p, size_t s, size_t n, const char* file, int line) { 837 | (void) file, (void) line; 838 | if (s == 0 || n == 0) 839 | Gif_Free(p); 840 | else if (s == 1 || n == 1 || s <= ((size_t) -1) / n) 841 | return realloc(p, s * n); 842 | return (void*) 0; 843 | } 844 | 845 | #undef Gif_Free 846 | void Gif_Free(void* p) { 847 | free(p); 848 | } 849 | #endif 850 | 851 | #ifdef __cplusplus 852 | } 853 | #endif 854 | -------------------------------------------------------------------------------- /GIFCompression/lib-gif-compression/src/gifread.c: -------------------------------------------------------------------------------- 1 | /* gifread.c - Functions to read GIFs. 2 | Copyright (C) 1997-2015 Eddie Kohler, ekohler@gmail.com 3 | This file is part of the LCDF GIF library. 4 | 5 | The LCDF GIF library is free software. It is distributed under the GNU 6 | General Public License, version 2; you can copy, distribute, or alter it at 7 | will, as long as this notice is kept intact and this source code is made 8 | available. There is no warranty, express or implied. */ 9 | 10 | #if HAVE_CONFIG_H 11 | # include 12 | #elif !defined(__cplusplus) 13 | /* Assume we don't have inline by default */ 14 | # define inline 15 | #endif 16 | #include "gif.h" 17 | #include 18 | #include 19 | #include 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | typedef struct { 25 | 26 | Gif_Stream *stream; 27 | 28 | Gif_Code *prefix; 29 | uint8_t *suffix; 30 | uint16_t *length; 31 | 32 | uint16_t width; 33 | uint16_t height; 34 | 35 | uint8_t *image; 36 | uint8_t *maximage; 37 | 38 | unsigned decodepos; 39 | 40 | Gif_Image* gfi; 41 | Gif_ReadErrorHandler handler; 42 | int errors[2]; 43 | 44 | } Gif_Context; 45 | 46 | 47 | typedef struct Gif_Reader { 48 | FILE *f; 49 | const uint8_t *v; 50 | uint32_t pos; 51 | uint32_t length; 52 | int is_record; 53 | int is_eoi; 54 | uint8_t (*byte_getter)(struct Gif_Reader *); 55 | uint32_t (*block_getter)(uint8_t*, uint32_t, struct Gif_Reader*); 56 | int (*eofer)(struct Gif_Reader *); 57 | } Gif_Reader; 58 | 59 | static Gif_ReadErrorHandler default_error_handler = 0; 60 | 61 | 62 | #define gifgetc(grr) ((char)(*grr->byte_getter)(grr)) 63 | #define gifgetbyte(grr) ((*grr->byte_getter)(grr)) 64 | #define gifgetblock(ptr, size, grr) ((*grr->block_getter)(ptr, size, grr)) 65 | #define gifeof(grr) ((*grr->eofer)(grr)) 66 | 67 | static inline uint16_t 68 | gifgetunsigned(Gif_Reader *grr) 69 | { 70 | uint8_t one = gifgetbyte(grr); 71 | uint8_t two = gifgetbyte(grr); 72 | return one | (two << 8); 73 | } 74 | 75 | 76 | static uint8_t 77 | file_byte_getter(Gif_Reader *grr) 78 | { 79 | int i = getc(grr->f); 80 | if (i != EOF) { 81 | ++grr->pos; 82 | return i; 83 | } else 84 | return 0; 85 | } 86 | 87 | static uint32_t 88 | file_block_getter(uint8_t *p, uint32_t s, Gif_Reader *grr) 89 | { 90 | size_t nread = fread(p, 1, s, grr->f); 91 | if (nread < s) 92 | memset(p + nread, 0, s - nread); 93 | grr->pos += nread; 94 | return nread; 95 | } 96 | 97 | static int 98 | file_eofer(Gif_Reader *grr) 99 | { 100 | int c = getc(grr->f); 101 | if (c == EOF) 102 | return 1; 103 | else { 104 | ungetc(c, grr->f); 105 | return 0; 106 | } 107 | } 108 | 109 | 110 | static uint8_t 111 | record_byte_getter(Gif_Reader *grr) 112 | { 113 | if (grr->pos < grr->length) 114 | return grr->v[grr->pos++]; 115 | else 116 | return 0; 117 | } 118 | 119 | static uint32_t 120 | record_block_getter(uint8_t *p, uint32_t s, Gif_Reader *grr) 121 | { 122 | uint32_t ncopy = (grr->pos + s <= grr->length ? s : grr->length - grr->pos); 123 | memcpy(p, &grr->v[grr->pos], ncopy); 124 | grr->pos += ncopy; 125 | if (ncopy < s) 126 | memset(p + ncopy, 0, s - ncopy); 127 | return ncopy; 128 | } 129 | 130 | static int 131 | record_eofer(Gif_Reader *grr) 132 | { 133 | return grr->pos == grr->length; 134 | } 135 | 136 | 137 | static void 138 | make_data_reader(Gif_Reader *grr, const uint8_t *data, uint32_t length) 139 | { 140 | grr->v = data; 141 | grr->pos = 0; 142 | grr->length = length; 143 | grr->is_record = 1; 144 | grr->byte_getter = record_byte_getter; 145 | grr->block_getter = record_block_getter; 146 | grr->eofer = record_eofer; 147 | } 148 | 149 | 150 | static void 151 | gif_read_error(Gif_Context *gfc, int is_error, const char *text) 152 | { 153 | Gif_ReadErrorHandler handler = gfc->handler ? gfc->handler : default_error_handler; 154 | if (is_error >= 0) 155 | gfc->errors[is_error > 0] += 1; 156 | if (handler) 157 | handler(gfc->stream, gfc->gfi, is_error, text); 158 | } 159 | 160 | 161 | static uint8_t 162 | one_code(Gif_Context *gfc, Gif_Code code) 163 | { 164 | uint8_t *suffixes = gfc->suffix; 165 | Gif_Code *prefixes = gfc->prefix; 166 | uint8_t *ptr; 167 | int lastsuffix = 0; 168 | int codelength = gfc->length[code]; 169 | 170 | gfc->decodepos += codelength; 171 | ptr = gfc->image + gfc->decodepos; 172 | while (codelength > 0) { 173 | lastsuffix = suffixes[code]; 174 | code = prefixes[code]; 175 | --ptr; 176 | if (ptr < gfc->maximage) 177 | *ptr = lastsuffix; 178 | --codelength; 179 | } 180 | 181 | /* return the first pixel in the code, which, since we walked backwards 182 | through the code, was the last suffix we processed. */ 183 | return lastsuffix; 184 | } 185 | 186 | static int 187 | read_image_block(Gif_Reader *grr, uint8_t *buffer, int *bit_pos_store, 188 | int *bit_len_store, int bits_needed) 189 | { 190 | int bit_position = *bit_pos_store; 191 | int bit_length = *bit_len_store; 192 | uint8_t block_len; 193 | 194 | while (bit_position + bits_needed > bit_length) { 195 | /* Read in the next data block. */ 196 | if (bit_position >= 8) { 197 | /* Need to shift down the upper, unused part of 'buffer' */ 198 | int i = bit_position / 8; 199 | buffer[0] = buffer[i]; 200 | buffer[1] = buffer[i+1]; 201 | bit_position -= i * 8; 202 | bit_length -= i * 8; 203 | } 204 | block_len = gifgetbyte(grr); 205 | GIF_DEBUG(("\nimage_block(%d) ", block_len)); 206 | if (block_len == 0) return 0; 207 | gifgetblock(buffer + bit_length / 8, block_len, grr); 208 | bit_length += block_len * 8; 209 | } 210 | 211 | *bit_pos_store = bit_position; 212 | *bit_len_store = bit_length; 213 | return 1; 214 | } 215 | 216 | 217 | static void 218 | read_image_data(Gif_Context *gfc, Gif_Reader *grr) 219 | { 220 | /* we need a bit more than GIF_MAX_BLOCK in case a single code is split 221 | across blocks */ 222 | uint8_t buffer[GIF_MAX_BLOCK + 5]; 223 | int i; 224 | uint32_t accum; 225 | 226 | int bit_position; 227 | int bit_length; 228 | 229 | Gif_Code code; 230 | Gif_Code old_code; 231 | Gif_Code clear_code; 232 | Gif_Code eoi_code; 233 | Gif_Code next_code; 234 | #define CUR_BUMP_CODE (1 << bits_needed) 235 | #define CUR_CODE_MASK ((1 << bits_needed) - 1) 236 | 237 | int min_code_size; 238 | int bits_needed; 239 | 240 | gfc->decodepos = 0; 241 | 242 | min_code_size = gifgetbyte(grr); 243 | GIF_DEBUG(("\n\nmin_code_size(%d) ", min_code_size)); 244 | if (min_code_size >= GIF_MAX_CODE_BITS) { 245 | gif_read_error(gfc, 1, "image corrupted, min_code_size too big"); 246 | min_code_size = GIF_MAX_CODE_BITS - 1; 247 | } else if (min_code_size < 2) { 248 | gif_read_error(gfc, 1, "image corrupted, min_code_size too small"); 249 | min_code_size = 2; 250 | } 251 | clear_code = 1 << min_code_size; 252 | for (code = 0; code < clear_code; code++) { 253 | gfc->prefix[code] = 49428; 254 | gfc->suffix[code] = (uint8_t)code; 255 | gfc->length[code] = 1; 256 | } 257 | eoi_code = clear_code + 1; 258 | 259 | next_code = eoi_code; 260 | bits_needed = min_code_size + 1; 261 | 262 | code = clear_code; 263 | 264 | bit_length = bit_position = 0; 265 | /* Thus the 'Read in the next data block.' code below will be invoked on the 266 | first time through: exactly right! */ 267 | 268 | while (1) { 269 | 270 | old_code = code; 271 | 272 | /* GET A CODE INTO THE 'code' VARIABLE. 273 | * 274 | * 9.Dec.1998 - Rather than maintain a byte pointer and a bit offset into 275 | * the current byte (and the processing associated with that), we maintain 276 | * one number: the offset, in bits, from the beginning of 'buffer'. This 277 | * much cleaner choice was inspired by Patrick J. Naughton 278 | * 's GIF-reading code, which does the same thing. 279 | * His code distributed as part of XV in xvgif.c. */ 280 | 281 | if (bit_position + bits_needed > bit_length) 282 | /* Read in the next data block. */ 283 | if (!read_image_block(grr, buffer, &bit_position, &bit_length, 284 | bits_needed)) 285 | goto zero_length_block; 286 | 287 | i = bit_position / 8; 288 | accum = buffer[i] + (buffer[i+1] << 8); 289 | if (bits_needed >= 8) 290 | accum |= (buffer[i+2]) << 16; 291 | code = (Gif_Code)((accum >> (bit_position % 8)) & CUR_CODE_MASK); 292 | bit_position += bits_needed; 293 | 294 | GIF_DEBUG(("%d ", code)); 295 | 296 | /* CHECK FOR SPECIAL OR BAD CODES: clear_code, eoi_code, or a code that is 297 | * too large. */ 298 | if (code == clear_code) { 299 | GIF_DEBUG(("clear ")); 300 | bits_needed = min_code_size + 1; 301 | next_code = eoi_code; 302 | continue; 303 | 304 | } else if (code == eoi_code) 305 | break; 306 | 307 | else if (code > next_code && next_code && next_code != clear_code) { 308 | /* code > next_code: a (hopefully recoverable) error. 309 | 310 | Bug fix, 5/27: Do this even if old_code == clear_code, and set code 311 | to 0 to prevent errors later. (If we didn't zero code, we'd later set 312 | old_code = code; then we had old_code >= next_code; so the prefixes 313 | array got all screwed up!) 314 | 315 | Bug fix, 4/12/2010: It is not an error if next_code == clear_code. 316 | This happens at the end of a large GIF: see the next comment ("If no 317 | meaningful next code should be defined...."). */ 318 | if (gfc->errors[1] < 20) 319 | gif_read_error(gfc, 1, "image corrupted, code out of range"); 320 | else if (gfc->errors[1] == 20) 321 | gif_read_error(gfc, 1, "(not reporting more errors)"); 322 | code = 0; 323 | } 324 | 325 | /* PROCESS THE CURRENT CODE and define the next code. If no meaningful 326 | * next code should be defined, then we have set next_code to either 327 | * 'eoi_code' or 'clear_code' -- so we'll store useless prefix/suffix data 328 | * in a useless place. */ 329 | 330 | /* *First,* set up the prefix and length for the next code 331 | (in case code == next_code). */ 332 | gfc->prefix[next_code] = old_code; 333 | gfc->length[next_code] = gfc->length[old_code] + 1; 334 | 335 | /* Use one_code to process code. It's nice that it returns the first 336 | pixel in code: that's what we need. */ 337 | gfc->suffix[next_code] = one_code(gfc, code); 338 | 339 | /* Special processing if code == next_code: we didn't know code's final 340 | suffix when we called one_code, but we do now. */ 341 | /* 7.Mar.2014 -- Avoid error if image has zero width/height. */ 342 | if (code == next_code && gfc->image + gfc->decodepos <= gfc->maximage) 343 | gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code]; 344 | 345 | /* Increment next_code except for the 'clear_code' special case (that's 346 | when we're reading at the end of a GIF) */ 347 | if (next_code != clear_code) { 348 | next_code++; 349 | if (next_code == CUR_BUMP_CODE) { 350 | if (bits_needed < GIF_MAX_CODE_BITS) 351 | bits_needed++; 352 | else 353 | next_code = clear_code; 354 | } 355 | } 356 | 357 | } 358 | 359 | /* read blocks until zero-length reached. */ 360 | i = gifgetbyte(grr); 361 | GIF_DEBUG(("\nafter_image(%d)\n", i)); 362 | while (i > 0) { 363 | gifgetblock(buffer, i, grr); 364 | i = gifgetbyte(grr); 365 | GIF_DEBUG(("\nafter_image(%d)\n", i)); 366 | } 367 | 368 | /* zero-length block reached. */ 369 | zero_length_block: { 370 | long delta = (long) (gfc->maximage - gfc->image) - (long) gfc->decodepos; 371 | char buf[BUFSIZ]; 372 | if (delta > 0) { 373 | sprintf(buf, "missing %ld %s of image data", delta, 374 | delta == 1 ? "pixel" : "pixels"); 375 | gif_read_error(gfc, 1, buf); 376 | } else if (delta < -1) { 377 | /* One pixel of superfluous data is OK; that could be the 378 | code == next_code case. */ 379 | sprintf(buf, "%ld superfluous pixels of image data", -delta); 380 | gif_read_error(gfc, 0, buf); 381 | } 382 | } 383 | } 384 | 385 | 386 | static Gif_Colormap * 387 | read_color_table(int size, Gif_Reader *grr) 388 | { 389 | Gif_Colormap *gfcm = Gif_NewFullColormap(size, size); 390 | Gif_Color *c; 391 | if (!gfcm) return 0; 392 | 393 | GIF_DEBUG(("colormap(%d) ", size)); 394 | for (c = gfcm->col; size; size--, c++) { 395 | c->gfc_red = gifgetbyte(grr); 396 | c->gfc_green = gifgetbyte(grr); 397 | c->gfc_blue = gifgetbyte(grr); 398 | c->haspixel = 0; 399 | } 400 | 401 | return gfcm; 402 | } 403 | 404 | 405 | static int 406 | read_logical_screen_descriptor(Gif_Stream *gfs, Gif_Reader *grr) 407 | /* returns 0 on memory error */ 408 | { 409 | uint8_t packed; 410 | 411 | /* we don't care about logical screen width or height */ 412 | gfs->screen_width = gifgetunsigned(grr); 413 | gfs->screen_height = gifgetunsigned(grr); 414 | 415 | packed = gifgetbyte(grr); 416 | gfs->background = gifgetbyte(grr); 417 | 418 | /* don't care about pixel aspect ratio */ 419 | gifgetbyte(grr); 420 | 421 | if (packed & 0x80) { /* have a global color table */ 422 | int ncol = 1 << ((packed & 0x07) + 1); 423 | gfs->global = read_color_table(ncol, grr); 424 | if (!gfs->global) return 0; 425 | gfs->global->refcount = 1; 426 | } else 427 | gfs->background = 256; 428 | 429 | return 1; 430 | } 431 | 432 | 433 | static int 434 | read_compressed_image(Gif_Image *gfi, Gif_Reader *grr, int read_flags) 435 | { 436 | if (grr->is_record) { 437 | const uint32_t image_pos = grr->pos; 438 | 439 | /* scan over image */ 440 | ++grr->pos; /* skip min code size */ 441 | while (grr->pos < grr->length) { 442 | int amt = grr->v[grr->pos]; 443 | grr->pos += amt + 1; 444 | if (amt == 0) 445 | break; 446 | } 447 | if (grr->pos > grr->length) 448 | grr->pos = grr->length; 449 | 450 | gfi->compressed_len = grr->pos - image_pos; 451 | if (read_flags & GIF_READ_CONST_RECORD) { 452 | gfi->compressed = (uint8_t*) &grr->v[image_pos]; 453 | gfi->free_compressed = 0; 454 | } else { 455 | gfi->compressed = Gif_NewArray(uint8_t, gfi->compressed_len); 456 | gfi->free_compressed = Gif_Free; 457 | if (!gfi->compressed) return 0; 458 | memcpy(gfi->compressed, &grr->v[image_pos], gfi->compressed_len); 459 | } 460 | 461 | } else { 462 | /* non-record; have to read it block by block. */ 463 | uint32_t comp_cap = 1024; 464 | uint32_t comp_len; 465 | uint8_t *comp = Gif_NewArray(uint8_t, comp_cap); 466 | int i; 467 | if (!comp) return 0; 468 | 469 | /* min code size */ 470 | i = gifgetbyte(grr); 471 | comp[0] = i; 472 | comp_len = 1; 473 | 474 | i = gifgetbyte(grr); 475 | while (i > 0) { 476 | /* add 2 before check so we don't have to check after loop when appending 477 | 0 block */ 478 | if (comp_len + i + 2 > comp_cap) { 479 | comp_cap *= 2; 480 | Gif_ReArray(comp, uint8_t, comp_cap); 481 | if (!comp) return 0; 482 | } 483 | comp[comp_len] = i; 484 | gifgetblock(comp + comp_len + 1, i, grr); 485 | comp_len += i + 1; 486 | i = gifgetbyte(grr); 487 | } 488 | comp[comp_len++] = 0; 489 | 490 | gfi->compressed = comp; 491 | gfi->compressed_len = comp_len; 492 | gfi->free_compressed = Gif_Free; 493 | } 494 | 495 | return 1; 496 | } 497 | 498 | 499 | static int 500 | uncompress_image(Gif_Context *gfc, Gif_Image *gfi, Gif_Reader *grr) 501 | { 502 | if (!Gif_CreateUncompressedImage(gfi, gfi->interlace)) 503 | return 0; 504 | gfc->width = gfi->width; 505 | gfc->height = gfi->height; 506 | gfc->image = gfi->image_data; 507 | gfc->maximage = gfi->image_data + (unsigned) gfi->width * (unsigned) gfi->height; 508 | read_image_data(gfc, grr); 509 | return 1; 510 | } 511 | 512 | 513 | int 514 | Gif_FullUncompressImage(Gif_Stream* gfs, Gif_Image* gfi, 515 | Gif_ReadErrorHandler h) 516 | { 517 | Gif_Context gfc; 518 | Gif_Reader grr; 519 | int ok = 0; 520 | 521 | /* return right away if image is already uncompressed. this might screw over 522 | people who expect re-uncompressing to restore the compressed version. */ 523 | if (gfi->img) 524 | return 2; 525 | if (gfi->image_data) 526 | /* we have uncompressed data, but not an 'img' array; 527 | this shouldn't happen */ 528 | return 0; 529 | 530 | gfc.stream = gfs; 531 | gfc.gfi = gfi; 532 | gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE); 533 | gfc.suffix = Gif_NewArray(uint8_t, GIF_MAX_CODE); 534 | gfc.length = Gif_NewArray(uint16_t, GIF_MAX_CODE); 535 | gfc.handler = h; 536 | gfc.errors[0] = gfc.errors[1] = 0; 537 | 538 | if (gfc.prefix && gfc.suffix && gfc.length && gfi->compressed) { 539 | make_data_reader(&grr, gfi->compressed, gfi->compressed_len); 540 | ok = uncompress_image(&gfc, gfi, &grr); 541 | } 542 | 543 | Gif_DeleteArray(gfc.prefix); 544 | Gif_DeleteArray(gfc.suffix); 545 | Gif_DeleteArray(gfc.length); 546 | if (gfc.errors[0] || gfc.errors[1]) 547 | gif_read_error(&gfc, -1, 0); 548 | return ok && !gfc.errors[1]; 549 | } 550 | 551 | 552 | static int 553 | read_image(Gif_Reader *grr, Gif_Context *gfc, Gif_Image *gfi, int read_flags) 554 | /* returns 0 on memory error */ 555 | { 556 | uint8_t packed; 557 | 558 | gfi->left = gifgetunsigned(grr); 559 | gfi->top = gifgetunsigned(grr); 560 | gfi->width = gifgetunsigned(grr); 561 | gfi->height = gifgetunsigned(grr); 562 | /* Mainline GIF processors (Firefox, etc.) process missing width (height) 563 | as screen_width (screen_height). */ 564 | if (gfi->width == 0) 565 | gfi->width = gfc->stream->screen_width; 566 | if (gfi->height == 0) 567 | gfi->height = gfc->stream->screen_height; 568 | /* If still zero, error. */ 569 | if (gfi->width == 0 || gfi->height == 0) { 570 | gif_read_error(gfc, 1, "image has zero width and/or height"); 571 | Gif_MakeImageEmpty(gfi); 572 | read_flags = 0; 573 | } 574 | /* If position out of range, error. */ 575 | if ((unsigned) gfi->left + (unsigned) gfi->width > 0xFFFF 576 | || (unsigned) gfi->top + (unsigned) gfi->height > 0xFFFF) { 577 | gif_read_error(gfc, 1, "image position and/or dimensions out of range"); 578 | Gif_MakeImageEmpty(gfi); 579 | read_flags = 0; 580 | } 581 | GIF_DEBUG(("<%ux%u> ", gfi->width, gfi->height)); 582 | 583 | packed = gifgetbyte(grr); 584 | if (packed & 0x80) { /* have a local color table */ 585 | int ncol = 1 << ((packed & 0x07) + 1); 586 | gfi->local = read_color_table(ncol, grr); 587 | if (!gfi->local) return 0; 588 | gfi->local->refcount = 1; 589 | } 590 | 591 | gfi->interlace = (packed & 0x40) != 0; 592 | 593 | /* Keep the compressed data if asked */ 594 | if (read_flags & GIF_READ_COMPRESSED) { 595 | if (!read_compressed_image(gfi, grr, read_flags)) 596 | return 0; 597 | if (read_flags & GIF_READ_UNCOMPRESSED) { 598 | Gif_Reader new_grr; 599 | make_data_reader(&new_grr, gfi->compressed, gfi->compressed_len); 600 | if (!uncompress_image(gfc, gfi, &new_grr)) 601 | return 0; 602 | } 603 | 604 | } else if (read_flags & GIF_READ_UNCOMPRESSED) { 605 | if (!uncompress_image(gfc, gfi, grr)) 606 | return 0; 607 | 608 | } else { 609 | /* skip over the image */ 610 | uint8_t buffer[GIF_MAX_BLOCK]; 611 | int i = gifgetbyte(grr); 612 | while (i > 0) { 613 | gifgetblock(buffer, i, grr); 614 | i = gifgetbyte(grr); 615 | } 616 | } 617 | 618 | return 1; 619 | } 620 | 621 | 622 | static void 623 | read_graphic_control_extension(Gif_Context *gfc, Gif_Image *gfi, 624 | Gif_Reader *grr) 625 | { 626 | uint8_t len; 627 | uint8_t crap[GIF_MAX_BLOCK]; 628 | 629 | len = gifgetbyte(grr); 630 | 631 | if (len == 4) { 632 | uint8_t packed = gifgetbyte(grr); 633 | gfi->disposal = (packed >> 2) & 0x07; 634 | gfi->delay = gifgetunsigned(grr); 635 | gfi->transparent = gifgetbyte(grr); 636 | if (!(packed & 0x01)) /* transparent color doesn't exist */ 637 | gfi->transparent = -1; 638 | len -= 4; 639 | } 640 | 641 | if (len > 0) { 642 | gif_read_error(gfc, 1, "bad graphic extension"); 643 | gifgetblock(crap, len, grr); 644 | } 645 | 646 | len = gifgetbyte(grr); 647 | while (len > 0) { 648 | gif_read_error(gfc, 1, "bad graphic extension"); 649 | gifgetblock(crap, len, grr); 650 | len = gifgetbyte(grr); 651 | } 652 | } 653 | 654 | 655 | static char *last_name; 656 | 657 | 658 | static char * 659 | suck_data(char *data, int *store_len, Gif_Reader *grr) 660 | { 661 | uint8_t len = gifgetbyte(grr); 662 | int total_len = 0; 663 | 664 | while (len > 0) { 665 | Gif_ReArray(data, char, total_len + len + 1); 666 | if (!data) return 0; 667 | gifgetblock((uint8_t *)data + total_len, len, grr); 668 | 669 | total_len += len; 670 | data[total_len] = 0; 671 | 672 | len = gifgetbyte(grr); 673 | } 674 | 675 | if (store_len) *store_len = total_len; 676 | return data; 677 | } 678 | 679 | 680 | static int 681 | read_unknown_extension(Gif_Context* gfc, Gif_Reader* grr, 682 | int kind, char* appname, int applength) 683 | { 684 | uint8_t block_len = gifgetbyte(grr); 685 | uint8_t* data = 0; 686 | int data_len = 0; 687 | Gif_Extension *gfex = 0; 688 | 689 | while (block_len > 0) { 690 | Gif_ReArray(data, uint8_t, data_len + block_len + 2); 691 | if (!data) 692 | goto done; 693 | data[data_len] = block_len; 694 | gifgetblock(data + data_len + 1, block_len, grr); 695 | data_len += block_len + 1; 696 | block_len = gifgetbyte(grr); 697 | } 698 | 699 | if (data) 700 | gfex = Gif_NewExtension(kind, appname, applength); 701 | if (gfex) { 702 | gfex->data = data; 703 | gfex->free_data = Gif_Free; 704 | gfex->length = data_len; 705 | gfex->packetized = 1; 706 | data[data_len] = 0; 707 | Gif_AddExtension(gfc->stream, gfc->gfi, gfex); 708 | } 709 | 710 | done: 711 | if (!gfex) 712 | Gif_DeleteArray(data); 713 | while (block_len > 0) { 714 | uint8_t buffer[GIF_MAX_BLOCK]; 715 | gifgetblock(buffer, block_len, grr); 716 | block_len = gifgetbyte(grr); 717 | } 718 | return gfex != 0; 719 | } 720 | 721 | 722 | static int 723 | read_application_extension(Gif_Context *gfc, Gif_Reader *grr) 724 | { 725 | Gif_Stream *gfs = gfc->stream; 726 | uint8_t buffer[GIF_MAX_BLOCK + 1]; 727 | uint8_t len = gifgetbyte(grr); 728 | gifgetblock(buffer, len, grr); 729 | 730 | /* Read the Netscape loop extension. */ 731 | if (len == 11 732 | && (memcmp(buffer, "NETSCAPE2.0", 11) == 0 733 | || memcmp(buffer, "ANIMEXTS1.0", 11) == 0)) { 734 | 735 | len = gifgetbyte(grr); 736 | if (len == 3) { 737 | gifgetbyte(grr); /* throw away the 1 */ 738 | gfs->loopcount = gifgetunsigned(grr); 739 | len = gifgetbyte(grr); 740 | if (len) 741 | gif_read_error(gfc, 1, "bad loop extension"); 742 | } else 743 | gif_read_error(gfc, 1, "bad loop extension"); 744 | 745 | while (len > 0) { 746 | gifgetblock(buffer, len, grr); 747 | len = gifgetbyte(grr); 748 | } 749 | return 1; 750 | 751 | } else 752 | return read_unknown_extension(gfc, grr, 0xFF, (char*)buffer, len); 753 | } 754 | 755 | 756 | static int 757 | read_comment_extension(Gif_Image *gfi, Gif_Reader *grr) 758 | { 759 | int len; 760 | Gif_Comment *gfcom = gfi->comment; 761 | char *m = suck_data(0, &len, grr); 762 | if (m) { 763 | if (!gfcom) 764 | gfcom = gfi->comment = Gif_NewComment(); 765 | if (!gfcom || !Gif_AddCommentTake(gfcom, m, len)) 766 | return 0; 767 | } 768 | return 1; 769 | } 770 | 771 | 772 | static Gif_Stream * 773 | read_gif(Gif_Reader *grr, int read_flags, 774 | const char* landmark, Gif_ReadErrorHandler handler) 775 | { 776 | Gif_Stream *gfs; 777 | Gif_Image *gfi; 778 | Gif_Context gfc; 779 | int unknown_block_type = 0; 780 | 781 | if (gifgetc(grr) != 'G' || 782 | gifgetc(grr) != 'I' || 783 | gifgetc(grr) != 'F') 784 | return 0; 785 | (void)gifgetc(grr); 786 | (void)gifgetc(grr); 787 | (void)gifgetc(grr); 788 | 789 | gfs = Gif_NewStream(); 790 | gfi = Gif_NewImage(); 791 | 792 | gfc.stream = gfs; 793 | gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE); 794 | gfc.suffix = Gif_NewArray(uint8_t, GIF_MAX_CODE); 795 | gfc.length = Gif_NewArray(uint16_t, GIF_MAX_CODE); 796 | gfc.handler = handler; 797 | gfc.gfi = gfi; 798 | gfc.errors[0] = gfc.errors[1] = 0; 799 | 800 | if (!gfs || !gfi || !gfc.prefix || !gfc.suffix || !gfc.length) 801 | goto done; 802 | gfs->landmark = landmark; 803 | 804 | GIF_DEBUG(("\nGIF ")); 805 | if (!read_logical_screen_descriptor(gfs, grr)) 806 | goto done; 807 | GIF_DEBUG(("logscrdesc ")); 808 | 809 | while (!gifeof(grr)) { 810 | 811 | uint8_t block = gifgetbyte(grr); 812 | 813 | switch (block) { 814 | 815 | case ',': /* image block */ 816 | GIF_DEBUG(("imageread %d ", gfs->nimages)); 817 | 818 | gfi->identifier = last_name; 819 | last_name = 0; 820 | if (!Gif_AddImage(gfs, gfi)) 821 | goto done; 822 | else if (!read_image(grr, &gfc, gfi, read_flags)) { 823 | Gif_RemoveImage(gfs, gfs->nimages - 1); 824 | goto done; 825 | } 826 | 827 | gfc.gfi = gfi = Gif_NewImage(); 828 | if (!gfi) 829 | goto done; 830 | break; 831 | 832 | case ';': /* terminator */ 833 | GIF_DEBUG(("term\n")); 834 | goto done; 835 | 836 | case '!': /* extension */ 837 | block = gifgetbyte(grr); 838 | GIF_DEBUG(("ext(0x%02X) ", block)); 839 | switch (block) { 840 | 841 | case 0xF9: 842 | read_graphic_control_extension(&gfc, gfi, grr); 843 | break; 844 | 845 | case 0xCE: 846 | last_name = suck_data(last_name, 0, grr); 847 | break; 848 | 849 | case 0xFE: 850 | if (!read_comment_extension(gfi, grr)) goto done; 851 | break; 852 | 853 | case 0xFF: 854 | read_application_extension(&gfc, grr); 855 | break; 856 | 857 | default: 858 | read_unknown_extension(&gfc, grr, block, 0, 0); 859 | break; 860 | 861 | } 862 | break; 863 | 864 | default: 865 | if (!unknown_block_type) { 866 | char buf[256]; 867 | sprintf(buf, "unknown block type %d at file offset %u", block, grr->pos - 1); 868 | gif_read_error(&gfc, 1, buf); 869 | unknown_block_type = 1; 870 | } 871 | break; 872 | 873 | } 874 | 875 | } 876 | 877 | done: 878 | 879 | /* Move comments and extensions after last image into stream. */ 880 | if (gfs && gfi) { 881 | Gif_Extension* gfex; 882 | gfs->end_comment = gfi->comment; 883 | gfi->comment = 0; 884 | gfs->end_extension_list = gfi->extension_list; 885 | gfi->extension_list = 0; 886 | for (gfex = gfs->end_extension_list; gfex; gfex = gfex->next) 887 | gfex->image = NULL; 888 | } 889 | 890 | Gif_DeleteImage(gfi); 891 | Gif_DeleteArray(last_name); 892 | Gif_DeleteArray(gfc.prefix); 893 | Gif_DeleteArray(gfc.suffix); 894 | Gif_DeleteArray(gfc.length); 895 | gfc.gfi = 0; 896 | 897 | if (gfs) 898 | gfs->errors = gfc.errors[1]; 899 | if (gfs && gfc.errors[1] == 0 900 | && !(read_flags & GIF_READ_TRAILING_GARBAGE_OK) 901 | && !grr->eofer(grr)) 902 | gif_read_error(&gfc, 0, "trailing garbage after GIF ignored"); 903 | /* finally, export last message */ 904 | gif_read_error(&gfc, -1, 0); 905 | 906 | return gfs; 907 | } 908 | 909 | 910 | Gif_Stream * 911 | Gif_FullReadFile(FILE *f, int read_flags, 912 | const char* landmark, Gif_ReadErrorHandler h) 913 | { 914 | Gif_Reader grr; 915 | if (!f) return 0; 916 | grr.f = f; 917 | grr.pos = 0; 918 | grr.is_record = 0; 919 | grr.byte_getter = file_byte_getter; 920 | grr.block_getter = file_block_getter; 921 | grr.eofer = file_eofer; 922 | return read_gif(&grr, read_flags, landmark, h); 923 | } 924 | 925 | Gif_Stream * 926 | Gif_FullReadRecord(const Gif_Record *gifrec, int read_flags, 927 | const char* landmark, Gif_ReadErrorHandler h) 928 | { 929 | Gif_Reader grr; 930 | if (!gifrec) return 0; 931 | make_data_reader(&grr, gifrec->data, gifrec->length); 932 | if (read_flags & GIF_READ_CONST_RECORD) 933 | read_flags |= GIF_READ_COMPRESSED; 934 | return read_gif(&grr, read_flags, landmark, h); 935 | } 936 | 937 | 938 | #undef Gif_ReadFile 939 | #undef Gif_ReadRecord 940 | 941 | Gif_Stream * 942 | Gif_ReadFile(FILE *f) 943 | { 944 | return Gif_FullReadFile(f, GIF_READ_UNCOMPRESSED, 0, 0); 945 | } 946 | 947 | Gif_Stream * 948 | Gif_ReadRecord(const Gif_Record *gifrec) 949 | { 950 | return Gif_FullReadRecord(gifrec, GIF_READ_UNCOMPRESSED, 0, 0); 951 | } 952 | 953 | void 954 | Gif_SetErrorHandler(Gif_ReadErrorHandler handler) { 955 | default_error_handler = handler; 956 | } 957 | 958 | #ifdef __cplusplus 959 | } 960 | #endif 961 | -------------------------------------------------------------------------------- /GIFCompression.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B82202211FE7E8930057DC2C /* GIFCompression.h in Headers */ = {isa = PBXBuildFile; fileRef = B822021F1FE7E8930057DC2C /* GIFCompression.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | B822028B1FE7EFE40057DC2C /* inttypes.h in Headers */ = {isa = PBXBuildFile; fileRef = B82202671FE7EFE40057DC2C /* inttypes.h */; }; 12 | B822028C1FE7EFE40057DC2C /* clp.h in Headers */ = {isa = PBXBuildFile; fileRef = B82202681FE7EFE40057DC2C /* clp.h */; }; 13 | B822028D1FE7EFE40057DC2C /* gif.h in Headers */ = {isa = PBXBuildFile; fileRef = B822026A1FE7EFE40057DC2C /* gif.h */; }; 14 | B82202921FE7EFE40057DC2C /* xform.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202701FE7EFE40057DC2C /* xform.c */; }; 15 | B82202951FE7EFE40057DC2C /* gifunopt.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202731FE7EFE40057DC2C /* gifunopt.c */; }; 16 | B82202971FE7EFE40057DC2C /* gifread.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202751FE7EFE40057DC2C /* gifread.c */; }; 17 | B82202981FE7EFE40057DC2C /* support.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202761FE7EFE40057DC2C /* support.c */; }; 18 | B82202991FE7EFE40057DC2C /* gifsicle.h in Headers */ = {isa = PBXBuildFile; fileRef = B82202771FE7EFE40057DC2C /* gifsicle.h */; }; 19 | B822029A1FE7EFE40057DC2C /* giffunc.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202781FE7EFE40057DC2C /* giffunc.c */; }; 20 | B822029D1FE7EFE40057DC2C /* quantize.c in Sources */ = {isa = PBXBuildFile; fileRef = B822027B1FE7EFE40057DC2C /* quantize.c */; }; 21 | B822029F1FE7EFE40057DC2C /* optimize.c in Sources */ = {isa = PBXBuildFile; fileRef = B822027D1FE7EFE40057DC2C /* optimize.c */; }; 22 | B82202A11FE7EFE40057DC2C /* strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = B822027F1FE7EFE40057DC2C /* strerror.c */; }; 23 | B82202A21FE7EFE40057DC2C /* gifwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202801FE7EFE40057DC2C /* gifwrite.c */; }; 24 | B82202A51FE7EFE40057DC2C /* kcolor.h in Headers */ = {isa = PBXBuildFile; fileRef = B82202831FE7EFE40057DC2C /* kcolor.h */; }; 25 | B82202A61FE7EFE40057DC2C /* gifsicle.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202841FE7EFE40057DC2C /* gifsicle.c */; }; 26 | B82202A71FE7EFE40057DC2C /* clp.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202851FE7EFE40057DC2C /* clp.c */; }; 27 | B82202A81FE7EFE40057DC2C /* merge.c in Sources */ = {isa = PBXBuildFile; fileRef = B82202891FE7EFE40057DC2C /* merge.c */; }; 28 | B82202B71FE7F0DA0057DC2C /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = B82202B61FE7F0DA0057DC2C /* config.h */; }; 29 | B871A0F21FE95478002144A7 /* gif_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = B871A0F11FE95478002144A7 /* gif_compress.c */; }; 30 | B871A0F41FE95AB0002144A7 /* GIFCompression.m in Sources */ = {isa = PBXBuildFile; fileRef = B871A0F31FE95AB0002144A7 /* GIFCompression.m */; }; 31 | B871A0FD1FE964E7002144A7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B871A0FC1FE964E7002144A7 /* AppDelegate.m */; }; 32 | B871A1001FE964E7002144A7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B871A0FF1FE964E7002144A7 /* ViewController.m */; }; 33 | B871A1031FE964E7002144A7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B871A1011FE964E7002144A7 /* Main.storyboard */; }; 34 | B871A1051FE964E7002144A7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B871A1041FE964E7002144A7 /* Assets.xcassets */; }; 35 | B871A1081FE964E7002144A7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B871A1061FE964E7002144A7 /* LaunchScreen.storyboard */; }; 36 | B871A10B1FE964E7002144A7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B871A10A1FE964E7002144A7 /* main.m */; }; 37 | B871A10F1FE9650C002144A7 /* GIFCompression.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B822021C1FE7E8930057DC2C /* GIFCompression.framework */; }; 38 | B871A1111FE9651B002144A7 /* GIFCompression.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B822021C1FE7E8930057DC2C /* GIFCompression.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 39 | B871A1161FE965D1002144A7 /* meme.gif in Resources */ = {isa = PBXBuildFile; fileRef = B871A1151FE965D1002144A7 /* meme.gif */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXContainerItemProxy section */ 43 | B871A1121FE9651B002144A7 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = B82202131FE7E8930057DC2C /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = B822021B1FE7E8930057DC2C; 48 | remoteInfo = GIFCompression; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXCopyFilesBuildPhase section */ 53 | B871A1141FE9651C002144A7 /* Embed Frameworks */ = { 54 | isa = PBXCopyFilesBuildPhase; 55 | buildActionMask = 2147483647; 56 | dstPath = ""; 57 | dstSubfolderSpec = 10; 58 | files = ( 59 | B871A1111FE9651B002144A7 /* GIFCompression.framework in Embed Frameworks */, 60 | ); 61 | name = "Embed Frameworks"; 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXCopyFilesBuildPhase section */ 65 | 66 | /* Begin PBXFileReference section */ 67 | B80A9EDA1FE8C528003D46CD /* opttemplate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opttemplate.c; sourceTree = ""; }; 68 | B822021C1FE7E8930057DC2C /* GIFCompression.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GIFCompression.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | B822021F1FE7E8930057DC2C /* GIFCompression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GIFCompression.h; sourceTree = ""; }; 70 | B82202201FE7E8930057DC2C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | B82202671FE7EFE40057DC2C /* inttypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inttypes.h; sourceTree = ""; }; 72 | B82202681FE7EFE40057DC2C /* clp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clp.h; sourceTree = ""; }; 73 | B822026A1FE7EFE40057DC2C /* gif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gif.h; sourceTree = ""; }; 74 | B82202701FE7EFE40057DC2C /* xform.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xform.c; sourceTree = ""; }; 75 | B82202731FE7EFE40057DC2C /* gifunopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gifunopt.c; sourceTree = ""; }; 76 | B82202751FE7EFE40057DC2C /* gifread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gifread.c; sourceTree = ""; }; 77 | B82202761FE7EFE40057DC2C /* support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = support.c; sourceTree = ""; }; 78 | B82202771FE7EFE40057DC2C /* gifsicle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gifsicle.h; sourceTree = ""; }; 79 | B82202781FE7EFE40057DC2C /* giffunc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = giffunc.c; sourceTree = ""; }; 80 | B822027B1FE7EFE40057DC2C /* quantize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quantize.c; sourceTree = ""; }; 81 | B822027D1FE7EFE40057DC2C /* optimize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = optimize.c; sourceTree = ""; }; 82 | B822027F1FE7EFE40057DC2C /* strerror.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = strerror.c; sourceTree = ""; }; 83 | B82202801FE7EFE40057DC2C /* gifwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gifwrite.c; sourceTree = ""; }; 84 | B82202831FE7EFE40057DC2C /* kcolor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kcolor.h; sourceTree = ""; }; 85 | B82202841FE7EFE40057DC2C /* gifsicle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gifsicle.c; sourceTree = ""; }; 86 | B82202851FE7EFE40057DC2C /* clp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = clp.c; sourceTree = ""; }; 87 | B82202891FE7EFE40057DC2C /* merge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = merge.c; sourceTree = ""; }; 88 | B82202AA1FE7F0130057DC2C /* libc++.1.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.1.tbd"; path = "usr/lib/libc++.1.tbd"; sourceTree = SDKROOT; }; 89 | B82202AC1FE7F0180057DC2C /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; 90 | B82202AE1FE7F01D0057DC2C /* libc++abi.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++abi.tbd"; path = "usr/lib/libc++abi.tbd"; sourceTree = SDKROOT; }; 91 | B82202B01FE7F0200057DC2C /* libstdc++.6.0.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.6.0.9.tbd"; path = "usr/lib/libstdc++.6.0.9.tbd"; sourceTree = SDKROOT; }; 92 | B82202B21FE7F0250057DC2C /* libstdc++.6.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.6.tbd"; path = "usr/lib/libstdc++.6.tbd"; sourceTree = SDKROOT; }; 93 | B82202B41FE7F0290057DC2C /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; 94 | B82202B61FE7F0DA0057DC2C /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; 95 | B871A0F01FE95453002144A7 /* gif_compress.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gif_compress.h; sourceTree = ""; }; 96 | B871A0F11FE95478002144A7 /* gif_compress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gif_compress.c; sourceTree = ""; }; 97 | B871A0F31FE95AB0002144A7 /* GIFCompression.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GIFCompression.m; sourceTree = ""; }; 98 | B871A0F91FE964E7002144A7 /* GIFLossyCompressExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GIFLossyCompressExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 99 | B871A0FB1FE964E7002144A7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 100 | B871A0FC1FE964E7002144A7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 101 | B871A0FE1FE964E7002144A7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 102 | B871A0FF1FE964E7002144A7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 103 | B871A1021FE964E7002144A7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 104 | B871A1041FE964E7002144A7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 105 | B871A1071FE964E7002144A7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 106 | B871A1091FE964E7002144A7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 107 | B871A10A1FE964E7002144A7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 108 | B871A1151FE965D1002144A7 /* meme.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = meme.gif; sourceTree = ""; }; 109 | /* End PBXFileReference section */ 110 | 111 | /* Begin PBXFrameworksBuildPhase section */ 112 | B82202181FE7E8930057DC2C /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | B871A0F61FE964E7002144A7 /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | B871A10F1FE9650C002144A7 /* GIFCompression.framework in Frameworks */, 124 | ); 125 | runOnlyForDeploymentPostprocessing = 0; 126 | }; 127 | /* End PBXFrameworksBuildPhase section */ 128 | 129 | /* Begin PBXGroup section */ 130 | B82202121FE7E8930057DC2C = { 131 | isa = PBXGroup; 132 | children = ( 133 | B822021E1FE7E8930057DC2C /* GIFCompression */, 134 | B871A0FA1FE964E7002144A7 /* GIFLossyCompressExample */, 135 | B822021D1FE7E8930057DC2C /* Products */, 136 | B82202A91FE7F0130057DC2C /* Frameworks */, 137 | ); 138 | sourceTree = ""; 139 | }; 140 | B822021D1FE7E8930057DC2C /* Products */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | B822021C1FE7E8930057DC2C /* GIFCompression.framework */, 144 | B871A0F91FE964E7002144A7 /* GIFLossyCompressExample.app */, 145 | ); 146 | name = Products; 147 | sourceTree = ""; 148 | }; 149 | B822021E1FE7E8930057DC2C /* GIFCompression */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | B82202411FE7EFC20057DC2C /* lib-gif-compression */, 153 | B822021F1FE7E8930057DC2C /* GIFCompression.h */, 154 | B871A0F31FE95AB0002144A7 /* GIFCompression.m */, 155 | B82202201FE7E8930057DC2C /* Info.plist */, 156 | ); 157 | path = GIFCompression; 158 | sourceTree = ""; 159 | }; 160 | B82202411FE7EFC20057DC2C /* lib-gif-compression */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | B82202651FE7EFE40057DC2C /* include */, 164 | B822026C1FE7EFE40057DC2C /* src */, 165 | ); 166 | path = "lib-gif-compression"; 167 | sourceTree = ""; 168 | }; 169 | B82202651FE7EFE40057DC2C /* include */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | B871A0F01FE95453002144A7 /* gif_compress.h */, 173 | ); 174 | path = include; 175 | sourceTree = ""; 176 | }; 177 | B822026C1FE7EFE40057DC2C /* src */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | B871A0F11FE95478002144A7 /* gif_compress.c */, 181 | B82202B61FE7F0DA0057DC2C /* config.h */, 182 | B82202771FE7EFE40057DC2C /* gifsicle.h */, 183 | B82202841FE7EFE40057DC2C /* gifsicle.c */, 184 | B82202671FE7EFE40057DC2C /* inttypes.h */, 185 | B822026A1FE7EFE40057DC2C /* gif.h */, 186 | B82202681FE7EFE40057DC2C /* clp.h */, 187 | B82202851FE7EFE40057DC2C /* clp.c */, 188 | B82202831FE7EFE40057DC2C /* kcolor.h */, 189 | B822027F1FE7EFE40057DC2C /* strerror.c */, 190 | B82202751FE7EFE40057DC2C /* gifread.c */, 191 | B82202801FE7EFE40057DC2C /* gifwrite.c */, 192 | B82202781FE7EFE40057DC2C /* giffunc.c */, 193 | B82202731FE7EFE40057DC2C /* gifunopt.c */, 194 | B82202701FE7EFE40057DC2C /* xform.c */, 195 | B82202761FE7EFE40057DC2C /* support.c */, 196 | B822027B1FE7EFE40057DC2C /* quantize.c */, 197 | B822027D1FE7EFE40057DC2C /* optimize.c */, 198 | B80A9EDA1FE8C528003D46CD /* opttemplate.c */, 199 | B82202891FE7EFE40057DC2C /* merge.c */, 200 | ); 201 | path = src; 202 | sourceTree = ""; 203 | }; 204 | B82202A91FE7F0130057DC2C /* Frameworks */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | B82202B41FE7F0290057DC2C /* libstdc++.tbd */, 208 | B82202B21FE7F0250057DC2C /* libstdc++.6.tbd */, 209 | B82202B01FE7F0200057DC2C /* libstdc++.6.0.9.tbd */, 210 | B82202AE1FE7F01D0057DC2C /* libc++abi.tbd */, 211 | B82202AC1FE7F0180057DC2C /* libc++.tbd */, 212 | B82202AA1FE7F0130057DC2C /* libc++.1.tbd */, 213 | ); 214 | name = Frameworks; 215 | sourceTree = ""; 216 | }; 217 | B871A0FA1FE964E7002144A7 /* GIFLossyCompressExample */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | B871A0FB1FE964E7002144A7 /* AppDelegate.h */, 221 | B871A0FC1FE964E7002144A7 /* AppDelegate.m */, 222 | B871A0FE1FE964E7002144A7 /* ViewController.h */, 223 | B871A0FF1FE964E7002144A7 /* ViewController.m */, 224 | B871A1151FE965D1002144A7 /* meme.gif */, 225 | B871A1011FE964E7002144A7 /* Main.storyboard */, 226 | B871A1041FE964E7002144A7 /* Assets.xcassets */, 227 | B871A1061FE964E7002144A7 /* LaunchScreen.storyboard */, 228 | B871A1091FE964E7002144A7 /* Info.plist */, 229 | B871A10A1FE964E7002144A7 /* main.m */, 230 | ); 231 | path = GIFLossyCompressExample; 232 | sourceTree = ""; 233 | }; 234 | /* End PBXGroup section */ 235 | 236 | /* Begin PBXHeadersBuildPhase section */ 237 | B82202191FE7E8930057DC2C /* Headers */ = { 238 | isa = PBXHeadersBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | B82202A51FE7EFE40057DC2C /* kcolor.h in Headers */, 242 | B82202991FE7EFE40057DC2C /* gifsicle.h in Headers */, 243 | B82202B71FE7F0DA0057DC2C /* config.h in Headers */, 244 | B822028C1FE7EFE40057DC2C /* clp.h in Headers */, 245 | B822028D1FE7EFE40057DC2C /* gif.h in Headers */, 246 | B822028B1FE7EFE40057DC2C /* inttypes.h in Headers */, 247 | B82202211FE7E8930057DC2C /* GIFCompression.h in Headers */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXHeadersBuildPhase section */ 252 | 253 | /* Begin PBXNativeTarget section */ 254 | B822021B1FE7E8930057DC2C /* GIFCompression */ = { 255 | isa = PBXNativeTarget; 256 | buildConfigurationList = B82202241FE7E8930057DC2C /* Build configuration list for PBXNativeTarget "GIFCompression" */; 257 | buildPhases = ( 258 | B82202171FE7E8930057DC2C /* Sources */, 259 | B82202181FE7E8930057DC2C /* Frameworks */, 260 | B82202191FE7E8930057DC2C /* Headers */, 261 | B822021A1FE7E8930057DC2C /* Resources */, 262 | ); 263 | buildRules = ( 264 | ); 265 | dependencies = ( 266 | ); 267 | name = GIFCompression; 268 | productName = GIFCompression; 269 | productReference = B822021C1FE7E8930057DC2C /* GIFCompression.framework */; 270 | productType = "com.apple.product-type.framework"; 271 | }; 272 | B871A0F81FE964E7002144A7 /* GIFLossyCompressExample */ = { 273 | isa = PBXNativeTarget; 274 | buildConfigurationList = B871A10C1FE964E7002144A7 /* Build configuration list for PBXNativeTarget "GIFLossyCompressExample" */; 275 | buildPhases = ( 276 | B871A0F51FE964E7002144A7 /* Sources */, 277 | B871A0F61FE964E7002144A7 /* Frameworks */, 278 | B871A0F71FE964E7002144A7 /* Resources */, 279 | B871A1141FE9651C002144A7 /* Embed Frameworks */, 280 | ); 281 | buildRules = ( 282 | ); 283 | dependencies = ( 284 | B871A1131FE9651B002144A7 /* PBXTargetDependency */, 285 | ); 286 | name = GIFLossyCompressExample; 287 | productName = GIFLossyCompressExample; 288 | productReference = B871A0F91FE964E7002144A7 /* GIFLossyCompressExample.app */; 289 | productType = "com.apple.product-type.application"; 290 | }; 291 | /* End PBXNativeTarget section */ 292 | 293 | /* Begin PBXProject section */ 294 | B82202131FE7E8930057DC2C /* Project object */ = { 295 | isa = PBXProject; 296 | attributes = { 297 | LastUpgradeCheck = 0920; 298 | ORGANIZATIONNAME = lenovo; 299 | TargetAttributes = { 300 | B822021B1FE7E8930057DC2C = { 301 | CreatedOnToolsVersion = 9.2; 302 | ProvisioningStyle = Automatic; 303 | }; 304 | B871A0F81FE964E7002144A7 = { 305 | CreatedOnToolsVersion = 9.2; 306 | ProvisioningStyle = Automatic; 307 | }; 308 | }; 309 | }; 310 | buildConfigurationList = B82202161FE7E8930057DC2C /* Build configuration list for PBXProject "GIFCompression" */; 311 | compatibilityVersion = "Xcode 8.0"; 312 | developmentRegion = en; 313 | hasScannedForEncodings = 0; 314 | knownRegions = ( 315 | en, 316 | Base, 317 | ); 318 | mainGroup = B82202121FE7E8930057DC2C; 319 | productRefGroup = B822021D1FE7E8930057DC2C /* Products */; 320 | projectDirPath = ""; 321 | projectRoot = ""; 322 | targets = ( 323 | B822021B1FE7E8930057DC2C /* GIFCompression */, 324 | B871A0F81FE964E7002144A7 /* GIFLossyCompressExample */, 325 | ); 326 | }; 327 | /* End PBXProject section */ 328 | 329 | /* Begin PBXResourcesBuildPhase section */ 330 | B822021A1FE7E8930057DC2C /* Resources */ = { 331 | isa = PBXResourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | B871A0F71FE964E7002144A7 /* Resources */ = { 338 | isa = PBXResourcesBuildPhase; 339 | buildActionMask = 2147483647; 340 | files = ( 341 | B871A1161FE965D1002144A7 /* meme.gif in Resources */, 342 | B871A1081FE964E7002144A7 /* LaunchScreen.storyboard in Resources */, 343 | B871A1051FE964E7002144A7 /* Assets.xcassets in Resources */, 344 | B871A1031FE964E7002144A7 /* Main.storyboard in Resources */, 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | /* End PBXResourcesBuildPhase section */ 349 | 350 | /* Begin PBXSourcesBuildPhase section */ 351 | B82202171FE7E8930057DC2C /* Sources */ = { 352 | isa = PBXSourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | B822029F1FE7EFE40057DC2C /* optimize.c in Sources */, 356 | B82202A61FE7EFE40057DC2C /* gifsicle.c in Sources */, 357 | B82202921FE7EFE40057DC2C /* xform.c in Sources */, 358 | B822029A1FE7EFE40057DC2C /* giffunc.c in Sources */, 359 | B871A0F21FE95478002144A7 /* gif_compress.c in Sources */, 360 | B82202A71FE7EFE40057DC2C /* clp.c in Sources */, 361 | B82202A81FE7EFE40057DC2C /* merge.c in Sources */, 362 | B82202A21FE7EFE40057DC2C /* gifwrite.c in Sources */, 363 | B82202981FE7EFE40057DC2C /* support.c in Sources */, 364 | B82202971FE7EFE40057DC2C /* gifread.c in Sources */, 365 | B822029D1FE7EFE40057DC2C /* quantize.c in Sources */, 366 | B871A0F41FE95AB0002144A7 /* GIFCompression.m in Sources */, 367 | B82202951FE7EFE40057DC2C /* gifunopt.c in Sources */, 368 | B82202A11FE7EFE40057DC2C /* strerror.c in Sources */, 369 | ); 370 | runOnlyForDeploymentPostprocessing = 0; 371 | }; 372 | B871A0F51FE964E7002144A7 /* Sources */ = { 373 | isa = PBXSourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | B871A1001FE964E7002144A7 /* ViewController.m in Sources */, 377 | B871A10B1FE964E7002144A7 /* main.m in Sources */, 378 | B871A0FD1FE964E7002144A7 /* AppDelegate.m in Sources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXSourcesBuildPhase section */ 383 | 384 | /* Begin PBXTargetDependency section */ 385 | B871A1131FE9651B002144A7 /* PBXTargetDependency */ = { 386 | isa = PBXTargetDependency; 387 | target = B822021B1FE7E8930057DC2C /* GIFCompression */; 388 | targetProxy = B871A1121FE9651B002144A7 /* PBXContainerItemProxy */; 389 | }; 390 | /* End PBXTargetDependency section */ 391 | 392 | /* Begin PBXVariantGroup section */ 393 | B871A1011FE964E7002144A7 /* Main.storyboard */ = { 394 | isa = PBXVariantGroup; 395 | children = ( 396 | B871A1021FE964E7002144A7 /* Base */, 397 | ); 398 | name = Main.storyboard; 399 | sourceTree = ""; 400 | }; 401 | B871A1061FE964E7002144A7 /* LaunchScreen.storyboard */ = { 402 | isa = PBXVariantGroup; 403 | children = ( 404 | B871A1071FE964E7002144A7 /* Base */, 405 | ); 406 | name = LaunchScreen.storyboard; 407 | sourceTree = ""; 408 | }; 409 | /* End PBXVariantGroup section */ 410 | 411 | /* Begin XCBuildConfiguration section */ 412 | B82202221FE7E8930057DC2C /* Debug */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | ALWAYS_SEARCH_USER_PATHS = NO; 416 | CLANG_ANALYZER_NONNULL = YES; 417 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 418 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 419 | CLANG_CXX_LIBRARY = "libc++"; 420 | CLANG_ENABLE_MODULES = YES; 421 | CLANG_ENABLE_OBJC_ARC = YES; 422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_COMMA = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 427 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 428 | CLANG_WARN_EMPTY_BODY = YES; 429 | CLANG_WARN_ENUM_CONVERSION = YES; 430 | CLANG_WARN_INFINITE_RECURSION = YES; 431 | CLANG_WARN_INT_CONVERSION = YES; 432 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 433 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 434 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 436 | CLANG_WARN_STRICT_PROTOTYPES = YES; 437 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 438 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 439 | CLANG_WARN_UNREACHABLE_CODE = YES; 440 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 441 | CODE_SIGN_IDENTITY = "iPhone Developer"; 442 | COPY_PHASE_STRIP = NO; 443 | CURRENT_PROJECT_VERSION = 1; 444 | DEBUG_INFORMATION_FORMAT = dwarf; 445 | ENABLE_STRICT_OBJC_MSGSEND = YES; 446 | ENABLE_TESTABILITY = YES; 447 | GCC_C_LANGUAGE_STANDARD = gnu11; 448 | GCC_DYNAMIC_NO_PIC = NO; 449 | GCC_NO_COMMON_BLOCKS = YES; 450 | GCC_OPTIMIZATION_LEVEL = 0; 451 | GCC_PREPROCESSOR_DEFINITIONS = ( 452 | "DEBUG=1", 453 | "$(inherited)", 454 | ); 455 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 456 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 457 | GCC_WARN_UNDECLARED_SELECTOR = YES; 458 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 459 | GCC_WARN_UNUSED_FUNCTION = YES; 460 | GCC_WARN_UNUSED_VARIABLE = YES; 461 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 462 | MTL_ENABLE_DEBUG_INFO = YES; 463 | ONLY_ACTIVE_ARCH = YES; 464 | SDKROOT = iphoneos; 465 | VERSIONING_SYSTEM = "apple-generic"; 466 | VERSION_INFO_PREFIX = ""; 467 | }; 468 | name = Debug; 469 | }; 470 | B82202231FE7E8930057DC2C /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | ALWAYS_SEARCH_USER_PATHS = NO; 474 | CLANG_ANALYZER_NONNULL = YES; 475 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 476 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 477 | CLANG_CXX_LIBRARY = "libc++"; 478 | CLANG_ENABLE_MODULES = YES; 479 | CLANG_ENABLE_OBJC_ARC = YES; 480 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 481 | CLANG_WARN_BOOL_CONVERSION = YES; 482 | CLANG_WARN_COMMA = YES; 483 | CLANG_WARN_CONSTANT_CONVERSION = YES; 484 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 485 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 486 | CLANG_WARN_EMPTY_BODY = YES; 487 | CLANG_WARN_ENUM_CONVERSION = YES; 488 | CLANG_WARN_INFINITE_RECURSION = YES; 489 | CLANG_WARN_INT_CONVERSION = YES; 490 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 491 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 492 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 493 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 494 | CLANG_WARN_STRICT_PROTOTYPES = YES; 495 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 496 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 497 | CLANG_WARN_UNREACHABLE_CODE = YES; 498 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 499 | CODE_SIGN_IDENTITY = "iPhone Developer"; 500 | COPY_PHASE_STRIP = NO; 501 | CURRENT_PROJECT_VERSION = 1; 502 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 503 | ENABLE_NS_ASSERTIONS = NO; 504 | ENABLE_STRICT_OBJC_MSGSEND = YES; 505 | GCC_C_LANGUAGE_STANDARD = gnu11; 506 | GCC_NO_COMMON_BLOCKS = YES; 507 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 508 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 509 | GCC_WARN_UNDECLARED_SELECTOR = YES; 510 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 511 | GCC_WARN_UNUSED_FUNCTION = YES; 512 | GCC_WARN_UNUSED_VARIABLE = YES; 513 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 514 | MTL_ENABLE_DEBUG_INFO = NO; 515 | SDKROOT = iphoneos; 516 | VALIDATE_PRODUCT = YES; 517 | VERSIONING_SYSTEM = "apple-generic"; 518 | VERSION_INFO_PREFIX = ""; 519 | }; 520 | name = Release; 521 | }; 522 | B82202251FE7E8930057DC2C /* Debug */ = { 523 | isa = XCBuildConfiguration; 524 | buildSettings = { 525 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 526 | CLANG_CXX_LIBRARY = "libc++"; 527 | CODE_SIGN_IDENTITY = ""; 528 | CODE_SIGN_STYLE = Automatic; 529 | DEFINES_MODULE = YES; 530 | DEVELOPMENT_TEAM = 7Z58D5ARBL; 531 | DYLIB_COMPATIBILITY_VERSION = 1; 532 | DYLIB_CURRENT_VERSION = 1; 533 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 534 | INFOPLIST_FILE = GIFCompression/Info.plist; 535 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 536 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 537 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 538 | MACH_O_TYPE = staticlib; 539 | ONLY_ACTIVE_ARCH = NO; 540 | PRODUCT_BUNDLE_IDENTIFIER = com.lenovo.GIFCompression; 541 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 542 | SKIP_INSTALL = YES; 543 | TARGETED_DEVICE_FAMILY = "1,2"; 544 | }; 545 | name = Debug; 546 | }; 547 | B82202261FE7E8930057DC2C /* Release */ = { 548 | isa = XCBuildConfiguration; 549 | buildSettings = { 550 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 551 | CLANG_CXX_LIBRARY = "libc++"; 552 | CODE_SIGN_IDENTITY = ""; 553 | CODE_SIGN_STYLE = Automatic; 554 | DEFINES_MODULE = YES; 555 | DEVELOPMENT_TEAM = 7Z58D5ARBL; 556 | DYLIB_COMPATIBILITY_VERSION = 1; 557 | DYLIB_CURRENT_VERSION = 1; 558 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 559 | INFOPLIST_FILE = GIFCompression/Info.plist; 560 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 561 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 562 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 563 | MACH_O_TYPE = staticlib; 564 | PRODUCT_BUNDLE_IDENTIFIER = com.lenovo.GIFCompression; 565 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 566 | SKIP_INSTALL = YES; 567 | TARGETED_DEVICE_FAMILY = "1,2"; 568 | }; 569 | name = Release; 570 | }; 571 | B871A10D1FE964E7002144A7 /* Debug */ = { 572 | isa = XCBuildConfiguration; 573 | buildSettings = { 574 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 575 | CODE_SIGN_STYLE = Automatic; 576 | DEVELOPMENT_TEAM = 7Z58D5ARBL; 577 | INFOPLIST_FILE = GIFLossyCompressExample/Info.plist; 578 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 579 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 580 | PRODUCT_BUNDLE_IDENTIFIER = com.lenovo.GIFLossyCompressExample; 581 | PRODUCT_NAME = "$(TARGET_NAME)"; 582 | TARGETED_DEVICE_FAMILY = "1,2"; 583 | }; 584 | name = Debug; 585 | }; 586 | B871A10E1FE964E7002144A7 /* Release */ = { 587 | isa = XCBuildConfiguration; 588 | buildSettings = { 589 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 590 | CODE_SIGN_STYLE = Automatic; 591 | DEVELOPMENT_TEAM = 7Z58D5ARBL; 592 | INFOPLIST_FILE = GIFLossyCompressExample/Info.plist; 593 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 594 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 595 | PRODUCT_BUNDLE_IDENTIFIER = com.lenovo.GIFLossyCompressExample; 596 | PRODUCT_NAME = "$(TARGET_NAME)"; 597 | TARGETED_DEVICE_FAMILY = "1,2"; 598 | }; 599 | name = Release; 600 | }; 601 | /* End XCBuildConfiguration section */ 602 | 603 | /* Begin XCConfigurationList section */ 604 | B82202161FE7E8930057DC2C /* Build configuration list for PBXProject "GIFCompression" */ = { 605 | isa = XCConfigurationList; 606 | buildConfigurations = ( 607 | B82202221FE7E8930057DC2C /* Debug */, 608 | B82202231FE7E8930057DC2C /* Release */, 609 | ); 610 | defaultConfigurationIsVisible = 0; 611 | defaultConfigurationName = Release; 612 | }; 613 | B82202241FE7E8930057DC2C /* Build configuration list for PBXNativeTarget "GIFCompression" */ = { 614 | isa = XCConfigurationList; 615 | buildConfigurations = ( 616 | B82202251FE7E8930057DC2C /* Debug */, 617 | B82202261FE7E8930057DC2C /* Release */, 618 | ); 619 | defaultConfigurationIsVisible = 0; 620 | defaultConfigurationName = Release; 621 | }; 622 | B871A10C1FE964E7002144A7 /* Build configuration list for PBXNativeTarget "GIFLossyCompressExample" */ = { 623 | isa = XCConfigurationList; 624 | buildConfigurations = ( 625 | B871A10D1FE964E7002144A7 /* Debug */, 626 | B871A10E1FE964E7002144A7 /* Release */, 627 | ); 628 | defaultConfigurationIsVisible = 0; 629 | defaultConfigurationName = Release; 630 | }; 631 | /* End XCConfigurationList section */ 632 | }; 633 | rootObject = B82202131FE7E8930057DC2C /* Project object */; 634 | } 635 | --------------------------------------------------------------------------------