├── ANGif ├── ANGifEncoder.h ├── ANGifEncoder.m ├── ANGifGraphicControlExt.h ├── ANGifGraphicControlExt.m ├── ANGifLogicalScreenDesc.h ├── ANGifLogicalScreenDesc.m ├── App Extensions │ ├── ANGifAppExtension.h │ ├── ANGifAppExtension.m │ ├── ANGifNetscapeAppExtension.h │ └── ANGifNetscapeAppExtension.m ├── ColorTable │ ├── ANAvgColorTable.h │ ├── ANAvgColorTable.m │ ├── ANColorTable.h │ ├── ANColorTable.m │ └── Cut │ │ ├── ANCutColorTable.h │ │ ├── ANCutColorTable.m │ │ ├── ANMutableColorArray.h │ │ └── ANMutableColorArray.m ├── ImageFrame │ ├── ANGifDataSubblock.h │ ├── ANGifDataSubblock.m │ ├── ANGifImageDescriptor.h │ ├── ANGifImageDescriptor.m │ ├── ANGifImageFrame.h │ ├── ANGifImageFrame.m │ └── ANGifImageFramePixelSource.h └── LZW │ ├── LZWBuffer.h │ ├── LZWBuffer.m │ ├── LZWSpoof.h │ └── LZWSpoof.m ├── ANNSImageGifPixelSource.h ├── ANNSImageGifPixelSource.m ├── GifPro.xcodeproj └── project.pbxproj ├── GifPro ├── ANAppDelegate.h ├── ANAppDelegate.m ├── ANExportWindow.h ├── ANExportWindow.m ├── ANImageListEntry.h ├── ANImageListEntry.m ├── GifPro-Info.plist ├── GifPro-Prefix.pch ├── NSImage+Resize.h ├── NSImage+Resize.m ├── en.lproj │ ├── Credits.rtf │ ├── InfoPlist.strings │ └── MainMenu.xib └── main.m └── README.md /ANGif/ANGifEncoder.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifEncoder.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANGifGraphicControlExt.h" 11 | #import "ANGifImageDescriptor.h" 12 | #import "ANGifLogicalScreenDesc.h" 13 | #import "ANAvgColorTable.h" 14 | #import "LZWSpoof.h" 15 | #import "ANGifDataSubblock.h" 16 | #import "ANGifAppExtension.h" 17 | 18 | #define kGifHeader "GIF89a" 19 | #define kGifTrailer "\x3B" 20 | 21 | @interface ANGifEncoder : NSObject { 22 | NSFileHandle * fileHandle; 23 | ANColorTable * globalColorTable; 24 | NSUInteger screenWidth; 25 | NSUInteger screenHeight; 26 | NSUInteger gctOffset; 27 | } 28 | 29 | /** 30 | * Creates a new ANGifEncoder with a given file handle, a canvas size, 31 | * and a global color table. 32 | * @param handle The output file handle that will be written to. 33 | * @param aSize The dimensions of the "virtual screen" created by 34 | * the gif decoder. 35 | * @param gct The global descriptor table, or nil if no GCT should be used. 36 | */ 37 | - (id)initWithFileHandle:(NSFileHandle *)handle size:(CGSize)aSize 38 | globalColorTable:(ANColorTable *)gct; 39 | 40 | /** 41 | * A call to this method is equivalent to a call to 42 | * initWithFileHandle:size:globalColorTable: with a valid file descriptor 43 | * opened for writing to fileName. 44 | */ 45 | - (id)initWithOutputFile:(NSString *)fileName size:(CGSize)aSize 46 | globalColorTable:(ANColorTable *)gct; 47 | 48 | /** 49 | * Add an application extension to the GIF file. 50 | */ 51 | - (void)addApplicationExtension:(ANGifAppExtension *)ext; 52 | 53 | /** 54 | * Add an image to the image sequence contained in the GIF file. 55 | */ 56 | - (void)addImageFrame:(ANGifImageFrame *)imageFrame; 57 | 58 | /** 59 | * Writes any headers and terminators that may need to get written. 60 | * @discussion This does not close the file handle. 61 | */ 62 | - (void)finishDataStream; 63 | 64 | /** 65 | * Calls finishDataStream before closing the underlying file handle. 66 | */ 67 | - (void)closeFile; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /ANGif/ANGifEncoder.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifEncoder.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifEncoder.h" 11 | 12 | @implementation ANGifEncoder 13 | 14 | - (id)initWithFileHandle:(NSFileHandle *)handle size:(CGSize)aSize 15 | globalColorTable:(ANColorTable *)gct { 16 | if ((self = [super init])) { 17 | if (!handle) return nil; 18 | #if __has_feature(objc_arc) 19 | globalColorTable = gct; 20 | fileHandle = handle; 21 | #else 22 | globalColorTable = [gct retain]; 23 | fileHandle = [handle retain]; 24 | #endif 25 | screenWidth = round(aSize.width); 26 | screenHeight = round(aSize.height); 27 | 28 | [handle writeData:[NSData dataWithBytes:kGifHeader length:strlen(kGifHeader)]]; 29 | 30 | // logical screen descriptor 31 | ANGifLogicalScreenDesc * screenDesc = [[ANGifLogicalScreenDesc alloc] init]; 32 | screenDesc.screenWidth = (UInt16)screenWidth; 33 | screenDesc.screenHeight = (UInt16)screenHeight; 34 | if (gct) { 35 | screenDesc.globalColorTable = YES; 36 | screenDesc.gctSize = 7; 37 | } 38 | [handle writeData:[screenDesc encodeBlock]]; 39 | #if !__has_feature(objc_arc) 40 | [screenDesc release]; 41 | #endif 42 | 43 | if (gct) { 44 | // write blank GCT, which will be re-written when the file 45 | // is closed 46 | gctOffset = [handle offsetInFile]; 47 | [handle writeData:[gct encodeRawColorTableCount:256]]; 48 | } 49 | } 50 | return self; 51 | } 52 | 53 | - (id)initWithOutputFile:(NSString *)fileName size:(CGSize)aSize 54 | globalColorTable:(ANColorTable *)gct { 55 | if (![[NSFileManager defaultManager] fileExistsAtPath:fileName]) { 56 | [[NSFileManager defaultManager] createFileAtPath:fileName contents:[NSData data] attributes:nil]; 57 | } 58 | self = [self initWithFileHandle:[NSFileHandle fileHandleForWritingAtPath:fileName] 59 | size:aSize globalColorTable:gct]; 60 | return self; 61 | } 62 | 63 | - (void)addApplicationExtension:(ANGifAppExtension *)ext { 64 | [fileHandle writeData:[ext encodeBlock]]; 65 | } 66 | 67 | - (void)addImageFrame:(ANGifImageFrame *)imageFrame { 68 | ANColorTable * colorTable = nil; 69 | NSData * imageData; 70 | 71 | if ([imageFrame localColorTable]) { 72 | colorTable = imageFrame.localColorTable; 73 | } else { 74 | colorTable = globalColorTable; 75 | } 76 | if (!colorTable) { 77 | #if __has_feature(objc_arc) 78 | imageFrame.localColorTable = [[ANAvgColorTable alloc] init]; 79 | #else 80 | imageFrame.localColorTable = [[[ANAvgColorTable alloc] init] autorelease]; 81 | #endif 82 | colorTable = imageFrame.localColorTable; 83 | } 84 | 85 | // - graphics control extension 86 | 87 | ANGifGraphicControlExt * gfxControl = [[ANGifGraphicControlExt alloc] init]; 88 | gfxControl.delayTime = imageFrame.delayTime; 89 | gfxControl.userInputFlag = NO; 90 | gfxControl.transparentColorFlag = [colorTable hasTransparentFirst]; 91 | gfxControl.transparentColorIndex = [colorTable transparentIndex]; 92 | [fileHandle writeData:[gfxControl encodeBlock]]; 93 | #if !__has_feature(objc_arc) 94 | [gfxControl release]; 95 | #endif 96 | 97 | // - image descriptor 98 | 99 | // calculate image data and re-arrange color table 100 | imageData = [imageFrame encodeImageUsingColorTable:colorTable]; 101 | 102 | ANGifImageDescriptor * descriptor = [[ANGifImageDescriptor alloc] initWithImageFrame:imageFrame]; 103 | [fileHandle writeData:[descriptor encodeBlock]]; 104 | #if !__has_feature(objc_arc) 105 | [descriptor release]; 106 | #endif 107 | 108 | // - local color table 109 | if (imageFrame.localColorTable) { 110 | // [colorTable sortByPriority]; 111 | [fileHandle writeData:[colorTable encodeRawColorTable]]; 112 | } 113 | 114 | // - and image itself 115 | UInt8 lzwSize = 8; 116 | [fileHandle writeData:[NSData dataWithBytes:&lzwSize length:1]]; 117 | 118 | NSData * lzwCompressed = [LZWSpoof lzwExpandData:imageData]; 119 | NSArray * imageBlocks = [ANGifDataSubblock dataSubblocksForData:lzwCompressed]; 120 | for (ANGifDataSubblock * subblock in imageBlocks) { 121 | [subblock writeToFileHandle:fileHandle]; 122 | } 123 | 124 | lzwSize = 0; 125 | [fileHandle writeData:[NSData dataWithBytes:&lzwSize length:1]]; // NULL terminator 126 | } 127 | 128 | - (void)finishDataStream { 129 | // write gif trailer 130 | [fileHandle writeData:[NSData dataWithBytes:kGifTrailer length:1]]; 131 | // rewrite GCT 132 | if (globalColorTable) { 133 | // [globalColorTable sortByPriority]; 134 | [fileHandle seekToFileOffset:gctOffset]; 135 | [fileHandle writeData:[globalColorTable encodeRawColorTableCount:256]]; 136 | } 137 | } 138 | 139 | - (void)closeFile { 140 | [self finishDataStream]; 141 | [fileHandle closeFile]; 142 | #if !__has_feature(objc_arc) 143 | [fileHandle release]; 144 | #endif 145 | fileHandle = nil; 146 | } 147 | 148 | #if !__has_feature(objc_arc) 149 | 150 | - (void)dealloc { 151 | [globalColorTable release]; 152 | [fileHandle release]; 153 | [super dealloc]; 154 | } 155 | 156 | #endif 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /ANGif/ANGifGraphicControlExt.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifGraphicControlExtension.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define kGraphicControlLabel 0xF9 12 | 13 | @interface ANGifGraphicControlExt : NSObject { 14 | BOOL userInputFlag; 15 | BOOL transparentColorFlag; 16 | UInt8 transparentColorIndex; 17 | NSTimeInterval delayTime; 18 | } 19 | 20 | @property (readwrite) BOOL userInputFlag; 21 | @property (readwrite) BOOL transparentColorFlag; 22 | @property (readwrite) UInt8 transparentColorIndex; 23 | @property (readwrite) NSTimeInterval delayTime; 24 | 25 | - (NSData *)encodeBlock; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ANGif/ANGifGraphicControlExt.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifGraphicControlExtension.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifGraphicControlExt.h" 11 | 12 | @implementation ANGifGraphicControlExt 13 | 14 | @synthesize userInputFlag; 15 | @synthesize transparentColorFlag; 16 | @synthesize transparentColorIndex; 17 | @synthesize delayTime; 18 | 19 | - (NSData *)encodeBlock { 20 | NSMutableData * encoded = [NSMutableData data]; 21 | UInt8 aByte = 0x21; 22 | UInt16 doubleByte; 23 | 24 | [encoded appendBytes:&aByte length:1]; // extension introducer 25 | aByte = kGraphicControlLabel; 26 | [encoded appendBytes:&aByte length:1]; // graphic control label 27 | aByte = 4; 28 | [encoded appendBytes:&aByte length:1]; // block length (fixed) 29 | 30 | // w/ disposal method #3 31 | aByte = (3 << 2) | (userInputFlag << 1) | transparentColorFlag; 32 | [encoded appendBytes:&aByte length:1]; 33 | 34 | doubleByte = (UInt16)round(delayTime * 100); 35 | [encoded appendBytes:&doubleByte length:2]; // delay time 36 | [encoded appendBytes:&transparentColorIndex length:1]; 37 | 38 | // terminator block 39 | aByte = 0; 40 | [encoded appendBytes:&aByte length:1]; 41 | 42 | return [NSData dataWithData:encoded]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ANGif/ANGifLogicalScreenDesc.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifLogicalScreenDescriptor.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANGifLogicalScreenDesc : NSObject { 12 | UInt16 screenWidth; 13 | UInt16 screenHeight; 14 | BOOL globalColorTable; 15 | UInt8 gtcSize; 16 | UInt8 backgroundColor; 17 | } 18 | 19 | @property (readwrite) UInt16 screenWidth; 20 | @property (readwrite) UInt16 screenHeight; 21 | @property (readwrite) BOOL globalColorTable; 22 | @property (readwrite) UInt8 gctSize; 23 | @property (readwrite) UInt8 backgroundColor; 24 | 25 | - (NSData *)encodeBlock; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ANGif/ANGifLogicalScreenDesc.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifLogicalScreenDescriptor.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifLogicalScreenDesc.h" 11 | 12 | @implementation ANGifLogicalScreenDesc 13 | 14 | @synthesize screenWidth; 15 | @synthesize screenHeight; 16 | @synthesize globalColorTable; 17 | @synthesize gctSize; 18 | @synthesize backgroundColor; 19 | 20 | - (NSData *)encodeBlock { 21 | NSMutableData * encoded = [NSMutableData data]; 22 | 23 | UInt8 aByte; 24 | 25 | [encoded appendBytes:&screenWidth length:2]; 26 | [encoded appendBytes:&screenHeight length:2]; 27 | // packed flags with 3*8 bits/pixel, GCT present, and GCT size 28 | aByte = (globalColorTable << 7) | (3 << 4) | (gctSize & 7); 29 | if (globalColorTable) { 30 | // aByte |= (1 << 3); // global color table sorted 31 | } 32 | [encoded appendBytes:&aByte length:1]; // flags 33 | [encoded appendBytes:&backgroundColor length:1]; 34 | aByte = 0; 35 | [encoded appendBytes:&aByte length:1]; // pixel aspect ratio 36 | 37 | return [NSData dataWithData:encoded]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ANGif/App Extensions/ANGifAppExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifAppExtension.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANGifAppExtension : NSObject { 12 | NSData * applicationIdentifier; 13 | NSData * applicationAuthCode; 14 | NSData * applicationData; 15 | } 16 | 17 | @property (nonatomic, retain) NSData * applicationIdentifier; 18 | @property (nonatomic, retain) NSData * applicationAuthCode; 19 | @property (nonatomic, retain) NSData * applicationData; 20 | 21 | - (NSData *)encodeBlock; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ANGif/App Extensions/ANGifAppExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifAppExtension.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifAppExtension.h" 11 | 12 | @implementation ANGifAppExtension 13 | 14 | @synthesize applicationIdentifier; 15 | @synthesize applicationAuthCode; 16 | @synthesize applicationData; 17 | 18 | - (NSData *)encodeBlock { 19 | NSMutableData * data = [NSMutableData data]; 20 | 21 | UInt8 aByte = 0x21; 22 | [data appendBytes:&aByte length:1]; // extension introducer 23 | aByte = 0xFF; 24 | [data appendBytes:&aByte length:1]; // extension label 25 | aByte = [applicationIdentifier length] + [applicationAuthCode length]; 26 | [data appendBytes:&aByte length:1]; // block length 27 | [data appendData:applicationIdentifier]; 28 | [data appendData:applicationAuthCode]; 29 | [data appendData:applicationData]; 30 | aByte = 0; 31 | [data appendBytes:&aByte length:1]; // application terminator 32 | 33 | return [NSData dataWithData:data]; 34 | } 35 | 36 | #if !__has_feature(objc_arc) 37 | 38 | - (void)dealloc { 39 | self.applicationIdentifier = nil; 40 | self.applicationAuthCode = nil; 41 | self.applicationData = nil; 42 | [super dealloc]; 43 | } 44 | 45 | #endif 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /ANGif/App Extensions/ANGifNetscapeAppExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifNetscapeAppExtension.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ANGifAppExtension.h" 10 | 11 | @interface ANGifNetscapeAppExtension : ANGifAppExtension { 12 | UInt16 numberOfRepeats; 13 | } 14 | 15 | @property (readonly) UInt16 numberOfRepeats; 16 | 17 | - (id)initWithRepeatCount:(UInt16)repeats; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ANGif/App Extensions/ANGifNetscapeAppExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifNetscapeAppExtension.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifNetscapeAppExtension.h" 11 | 12 | @implementation ANGifNetscapeAppExtension 13 | 14 | @synthesize numberOfRepeats; 15 | 16 | - (id)init { 17 | if ((self = [self initWithRepeatCount:0xffff])) { 18 | } 19 | return self; 20 | } 21 | 22 | - (id)initWithRepeatCount:(UInt16)repeats { 23 | if ((self = [super init])) { 24 | numberOfRepeats = repeats; 25 | // calculate application data 26 | NSMutableData * appData = [NSMutableData data]; 27 | [appData appendBytes:"\x03\x01" length:2]; 28 | [appData appendBytes:&numberOfRepeats length:2]; 29 | self.applicationData = [NSData dataWithData:appData]; 30 | // app ID and signature 31 | self.applicationIdentifier = [NSData dataWithBytes:"\x4E\x45\x54\x53\x43\x41\x50\x45" length:8]; 32 | self.applicationAuthCode = [NSData dataWithBytes:"\x32\x2E\x30" length:3]; 33 | } 34 | return self; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ANGif/ColorTable/ANAvgColorTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifBasicColorTable.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ANColorTable.h" 10 | 11 | @interface ANAvgColorTable : ANColorTable { 12 | 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ANGif/ColorTable/ANAvgColorTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifBasicColorTable.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANAvgColorTable.h" 11 | 12 | @implementation ANAvgColorTable 13 | 14 | - (UInt8)addColor:(ANGifColor)aColor { 15 | NSUInteger firstIndex = (self.hasTransparentFirst ? 1 : 0); 16 | UInt8 bestToCut = firstIndex; 17 | NSUInteger variance = UINT_MAX; 18 | 19 | for (NSUInteger index = firstIndex; index < _entryCount; index++) { 20 | NSUInteger lvariance = 0; 21 | ANGifColor color = [self colorAtIndex:index]; 22 | lvariance += abs((int)color.red - (int)aColor.red); 23 | lvariance += abs((int)color.green - (int)aColor.green); 24 | lvariance += abs((int)color.blue - (int)aColor.blue); 25 | lvariance *= _entries[index].priority; 26 | if (lvariance < variance) { 27 | bestToCut = index; 28 | variance = lvariance; 29 | if (lvariance == 0) return bestToCut; 30 | } 31 | } 32 | 33 | if (_entryCount < maxColors && variance > 10) { 34 | return [super addColor:aColor]; 35 | } 36 | 37 | // do a cut 38 | ANGifColor cutColor = [self colorAtIndex:bestToCut]; 39 | cutColor = ANGifColorAverage(cutColor, aColor); 40 | _entries[bestToCut].color = cutColor; 41 | 42 | _entries[bestToCut].priority += 1; 43 | return bestToCut; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /ANGif/ColorTable/ANColorTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifColorTable.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef struct { 12 | UInt8 red; 13 | UInt8 green; 14 | UInt8 blue; 15 | } ANGifColor; 16 | 17 | BOOL ANGifColorIsEqual (ANGifColor color1, ANGifColor color2); 18 | NSUInteger ANGifColorVariance (ANGifColor color1, ANGifColor color2); 19 | ANGifColor ANGifColorAverage (ANGifColor color1, ANGifColor color2); 20 | ANGifColor ANGifColorMake (UInt8 red, UInt8 green, UInt8 blue); 21 | 22 | typedef struct { 23 | ANGifColor color; 24 | NSUInteger priority; 25 | } ANGifColorTableEntry; 26 | 27 | #define ANGifColorIndexOutOfBoundsException @"ANGifColorIndexOutOfBoundsException" 28 | #define ANGifColorTableFullException @"ANGifColorTableFullException" 29 | 30 | @interface ANColorTable : NSObject { 31 | ANGifColorTableEntry * _entries; 32 | NSUInteger _entryCount; 33 | NSUInteger _totalAlloced; 34 | NSUInteger maxColors; 35 | BOOL hasTransparentFirst; 36 | } 37 | 38 | @property (readwrite) NSUInteger maxColors; 39 | @property (readonly) BOOL hasTransparentFirst; 40 | 41 | - (id)initWithTransparentFirst:(BOOL)transparentFirst; 42 | 43 | - (NSUInteger)numberOfEntries; 44 | - (void)setColor:(ANGifColor)color atIndex:(UInt8)index; 45 | - (UInt8)addColor:(ANGifColor)aColor; 46 | - (ANGifColor)colorAtIndex:(UInt8)index; 47 | - (UInt8)transparentIndex; 48 | 49 | - (void)sortByPriority; 50 | - (BOOL)singleSortStep; 51 | 52 | /** 53 | * Returns a value x where 2^(x + 1) is the number (or more than the number) 54 | * of entries in this color table. 55 | */ 56 | - (UInt8)colorTableSizeValue; 57 | - (NSData *)encodeRawColorTable; 58 | - (NSData *)encodeRawColorTableCount:(NSUInteger)numEntries; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /ANGif/ColorTable/ANColorTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifColorTable.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANColorTable.h" 11 | 12 | @implementation ANColorTable 13 | 14 | @synthesize maxColors; 15 | @synthesize hasTransparentFirst; 16 | 17 | - (id)initWithTransparentFirst:(BOOL)transparentFirst { 18 | if ((self = [self init])) { 19 | ANGifColor myColor; 20 | myColor.red = 0; 21 | myColor.green = 0; 22 | myColor.blue = 0; 23 | [self addColor:myColor]; 24 | hasTransparentFirst = transparentFirst; 25 | } 26 | return self; 27 | } 28 | 29 | - (id)init { 30 | if ((self = [super init])) { 31 | _entries = (ANGifColorTableEntry *)malloc(sizeof(ANGifColorTableEntry)); 32 | _totalAlloced = 1; 33 | maxColors = 256; 34 | } 35 | return self; 36 | } 37 | 38 | - (NSUInteger)numberOfEntries { 39 | return _entryCount; 40 | } 41 | 42 | - (void)setColor:(ANGifColor)color atIndex:(UInt8)index { 43 | if (index >= _entryCount) { 44 | @throw [NSException exceptionWithName:ANGifColorIndexOutOfBoundsException 45 | reason:@"The specified color index was beyond the bounds of the color table." 46 | userInfo:nil]; 47 | } 48 | _entries[index].color = color; 49 | _entries[index].priority = 1; 50 | } 51 | 52 | - (UInt8)addColor:(ANGifColor)aColor { 53 | for (NSUInteger i = (self.hasTransparentFirst ? 1 : 0); i < _entryCount; i++) { 54 | if (ANGifColorIsEqual(_entries[i].color, aColor)) { 55 | _entries[i].priority += 1; 56 | return (UInt8)i; 57 | } 58 | } 59 | if (_entryCount >= maxColors) { 60 | @throw [NSException exceptionWithName:ANGifColorTableFullException reason:nil userInfo:nil]; 61 | } 62 | if (_entryCount == _totalAlloced) { 63 | _totalAlloced += 3; 64 | if (_totalAlloced > maxColors) _totalAlloced = maxColors; 65 | _entries = (ANGifColorTableEntry *)realloc(_entries, sizeof(ANGifColorTableEntry) * _totalAlloced); 66 | } 67 | _entries[_entryCount].color = aColor; 68 | _entries[_entryCount].priority = 1; 69 | return _entryCount++; 70 | } 71 | 72 | - (ANGifColor)colorAtIndex:(UInt8)index { 73 | if (index >= _entryCount) { 74 | @throw [NSException exceptionWithName:ANGifColorIndexOutOfBoundsException 75 | reason:@"The specified color index was beyond the bounds of the color table." 76 | userInfo:nil]; 77 | } 78 | return _entries[index].color; 79 | } 80 | 81 | - (UInt8)transparentIndex { 82 | return 0; 83 | } 84 | 85 | - (void)dealloc { 86 | free(_entries); 87 | #if !__has_feature(objc_arc) 88 | [super dealloc]; 89 | #endif 90 | } 91 | 92 | #pragma mark - Sorting - 93 | 94 | - (void)sortByPriority { 95 | while ([self singleSortStep]); 96 | } 97 | 98 | - (BOOL)singleSortStep { 99 | if (_entryCount == (self.hasTransparentFirst ? 1 : 0)) return NO; 100 | ANGifColorTableEntry lastEntry = _entries[(self.hasTransparentFirst ? 1 : 0)]; 101 | for (NSUInteger i = (self.hasTransparentFirst ? 2 : 1); i < _entryCount; i++) { 102 | ANGifColorTableEntry entry = _entries[i]; 103 | if (entry.priority > lastEntry.priority) { 104 | // swap order 105 | _entries[i] = lastEntry; 106 | _entries[i - 1] = entry; 107 | return YES; 108 | } 109 | lastEntry = entry; 110 | } 111 | return NO; 112 | } 113 | 114 | #pragma mark Encoding 115 | 116 | - (UInt8)colorTableSizeValue { 117 | for (NSUInteger x = 0; x < 8; x++) { 118 | // test the value 119 | NSUInteger countValue = 1 << (x + 1); 120 | if (countValue >= _entryCount) { 121 | return x; 122 | } 123 | } 124 | return 7; 125 | } 126 | 127 | - (NSData *)encodeRawColorTable { 128 | UInt8 tableSize = [self colorTableSizeValue]; 129 | NSUInteger numEntries = 1 << ((NSUInteger)tableSize + 1); 130 | return [self encodeRawColorTableCount:numEntries]; 131 | } 132 | 133 | - (NSData *)encodeRawColorTableCount:(NSUInteger)numEntries { 134 | NSMutableData * encoded = [NSMutableData data]; 135 | 136 | UInt8 byte; 137 | for (NSUInteger i = 0; i < numEntries; i++) { 138 | if (i >= _entryCount) { 139 | // add empty entry 140 | byte = 0; 141 | [encoded appendBytes:&byte length:1]; 142 | [encoded appendBytes:&byte length:1]; 143 | [encoded appendBytes:&byte length:1]; 144 | } else { 145 | ANGifColor color = [self colorAtIndex:(UInt8)i]; 146 | [encoded appendBytes:&color.red length:1]; 147 | [encoded appendBytes:&color.green length:1]; 148 | [encoded appendBytes:&color.blue length:1]; 149 | } 150 | } 151 | 152 | return [NSData dataWithData:encoded]; 153 | } 154 | 155 | @end 156 | 157 | BOOL ANGifColorIsEqual (ANGifColor color1, ANGifColor color2) { 158 | if (color1.red == color2.red && color1.green == color2.green && color1.blue == color2.blue) { 159 | return YES; 160 | } 161 | return NO; 162 | } 163 | 164 | NSUInteger ANGifColorVariance (ANGifColor color1, ANGifColor color2) { 165 | NSUInteger v = 0; 166 | v += abs((int)color1.red - (int)color2.red); 167 | v += abs((int)color1.green - (int)color2.green); 168 | v += abs((int)color1.blue - (int)color2.blue); 169 | return v; 170 | } 171 | 172 | ANGifColor ANGifColorAverage (ANGifColor color1, ANGifColor color2) { 173 | ANGifColor median; 174 | median.red = (UInt8)round(((double)color1.red + (double)color2.red) / 2.0); 175 | median.green = (UInt8)round(((double)color1.green + (double)color2.green) / 2.0); 176 | median.blue = (UInt8)round(((double)color1.blue + (double)color2.blue) / 2.0); 177 | return median; 178 | } 179 | 180 | ANGifColor ANGifColorMake (UInt8 red, UInt8 green, UInt8 blue) { 181 | ANGifColor color; 182 | color.red = red; 183 | color.green = green; 184 | color.blue = blue; 185 | return color; 186 | } 187 | -------------------------------------------------------------------------------- /ANGif/ColorTable/Cut/ANCutColorTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANCutColorTable.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #define kColorTableSamplePoints 512 10 | 11 | #import "ANColorTable.h" 12 | #import "ANGifImageFramePixelSource.h" 13 | #import "ANMutableColorArray.h" 14 | 15 | @interface ANCutColorTable : ANColorTable { 16 | BOOL finishedInit; 17 | } 18 | 19 | /** 20 | * Create a new cut based color table with a given pixel source. 21 | * @param hasAlpha YES if the color table should have a transparent color reserved, NO otherwise. 22 | * @param pixelSource The pixel source from which pixels will be sampled. 23 | */ 24 | - (id)initWithTransparentFirst:(BOOL)hasAlpha pixelSource:(id)pixelSource; 25 | 26 | /** 27 | * Create a new cut based color table with a given pixel source. 28 | * @param hasAlpha YES if the color table should have a transparent color reserved, NO otherwise. 29 | * @param pixelSource The pixel source from which pixels will be sampled. 30 | * @param count The number of pixels to sample. Increasing this value will increase the 31 | * accuracy of the color table, but will decrease performance. 32 | */ 33 | - (id)initWithTransparentFirst:(BOOL)hasAlpha pixelSource:(id)pixelSource samples:(NSUInteger)count; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /ANGif/ColorTable/Cut/ANCutColorTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANCutColorTable.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANCutColorTable.h" 11 | 12 | @implementation ANCutColorTable 13 | 14 | - (id)initWithTransparentFirst:(BOOL)hasAlpha pixelSource:(id)pixelSource { 15 | return (self = [self initWithTransparentFirst:hasAlpha pixelSource:pixelSource samples:kColorTableSamplePoints]); 16 | } 17 | 18 | - (id)initWithTransparentFirst:(BOOL)hasAlpha pixelSource:(id)pixelSource samples:(NSUInteger)count { 19 | if ((self = [super initWithTransparentFirst:hasAlpha])) { 20 | ANMutableColorArray * colorArray = [[ANMutableColorArray alloc] init]; 21 | NSUInteger color[4]; 22 | NSUInteger numberOfPoints = count; 23 | NSUInteger totalPixels = [pixelSource pixelsWide] * [pixelSource pixelsHigh]; 24 | double pixelsPerSample = (double)totalPixels / (double)numberOfPoints; 25 | if (pixelsPerSample < 1) pixelsPerSample = 1; 26 | double pixelIndex = 0; 27 | BOOL hasTransparency = [pixelSource hasTransparency]; 28 | for (NSUInteger y = 0; y < [pixelSource pixelsHigh]; y++) { 29 | for (NSUInteger x = 0; x < [pixelSource pixelsWide]; x++) { 30 | pixelIndex += 1.0; 31 | if (pixelIndex >= pixelsPerSample) { 32 | pixelIndex -= pixelsPerSample; 33 | ANGifColor aColor; 34 | [pixelSource getPixel:color atX:x y:y]; 35 | if (!(color[3] < 0x20 && hasTransparency && hasAlpha)) { 36 | aColor.red = color[0]; 37 | aColor.green = color[1]; 38 | aColor.blue = color[2]; 39 | [colorArray addColor:aColor]; 40 | } 41 | } 42 | } 43 | } 44 | [colorArray sortByBrightness]; 45 | // split colorArray up if needed, create new color array 46 | NSUInteger maxGenColors = (hasAlpha ? 254 : 255); 47 | if ([colorArray count] > maxGenColors) { 48 | #if !__has_feature(objc_arc) 49 | [colorArray autorelease]; 50 | #endif 51 | colorArray = [colorArray colorArrayByAveragingSplit:maxGenColors]; 52 | #if !__has_feature(objc_arc) 53 | [colorArray retain]; 54 | #endif 55 | } 56 | for (NSUInteger i = 0; i < [colorArray count]; i++) { 57 | [super addColor:[colorArray colorAtIndex:i]]; 58 | } 59 | 60 | #if !__has_feature(objc_arc) 61 | [colorArray release]; 62 | #endif 63 | 64 | finishedInit = YES; 65 | } 66 | return self; 67 | } 68 | 69 | - (UInt8)addColor:(ANGifColor)aColor { 70 | if (!finishedInit) { 71 | return [super addColor:aColor]; 72 | } 73 | 74 | UInt8 firstIndex = (self.hasTransparentFirst ? 1 : 0); 75 | NSUInteger variance = INT_MAX; 76 | UInt8 selectedColor = firstIndex; 77 | for (NSUInteger i = firstIndex; i < _entryCount; i++) { 78 | ANGifColor color = [self colorAtIndex:i]; 79 | NSUInteger lvariance = ANGifColorVariance(color, aColor); 80 | if (lvariance < variance) { 81 | variance = lvariance; 82 | selectedColor = i; 83 | } 84 | } 85 | 86 | return selectedColor; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /ANGif/ColorTable/Cut/ANMutableColorArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANMutableColorArray.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANColorTable.h" 11 | 12 | @interface ANMutableColorArray : NSObject { 13 | ANGifColor * _colors; 14 | NSUInteger _entryCount; 15 | NSUInteger _totalAlloced; 16 | } 17 | 18 | - (NSUInteger)count; 19 | - (void)addColor:(ANGifColor)color; 20 | - (void)removeAtIndex:(NSUInteger)index; 21 | - (ANGifColor)colorAtIndex:(NSUInteger)index; 22 | 23 | - (void)sortByBrightness; 24 | - (ANMutableColorArray *)colorArrayByAveragingSplit:(NSUInteger)numColors; 25 | - (void)removeDuplicates; 26 | - (ANGifColor)averagePopFirst; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ANGif/ColorTable/Cut/ANMutableColorArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANMutableColorArray.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANMutableColorArray.h" 11 | #define kColorBufferSize 256 12 | 13 | int CompareColorQSort (const void * ent1, const void * ent2); 14 | 15 | @implementation ANMutableColorArray 16 | 17 | - (id)init { 18 | if ((self = [super init])) { 19 | _colors = (ANGifColor *)malloc(sizeof(ANGifColor) * kColorBufferSize); 20 | _totalAlloced = kColorBufferSize; 21 | } 22 | return self; 23 | } 24 | 25 | - (NSUInteger)count { 26 | return _entryCount; 27 | } 28 | 29 | - (void)addColor:(ANGifColor)color { 30 | for (NSUInteger i = 0; i < _entryCount; i++) { 31 | ANGifColor aColor = [self colorAtIndex:i]; 32 | if (ANGifColorVariance(color, aColor) < 5) return; 33 | } 34 | if (_entryCount + 1 == _totalAlloced) { 35 | _totalAlloced += kColorBufferSize; 36 | _colors = (ANGifColor *)realloc(_colors, sizeof(ANGifColor) * _totalAlloced); 37 | } 38 | _colors[_entryCount++] = color; 39 | } 40 | 41 | - (void)removeAtIndex:(NSUInteger)index { 42 | NSUInteger assignIndex = 0; 43 | for (NSUInteger i = 0; i < _entryCount; i++) { 44 | if (i != index) { 45 | _colors[assignIndex++] = _colors[i]; 46 | } 47 | } 48 | _entryCount = assignIndex; 49 | if (_totalAlloced - kColorBufferSize >= _entryCount && _totalAlloced > kColorBufferSize) { 50 | _totalAlloced -= kColorBufferSize; 51 | _colors = (ANGifColor *)realloc(_colors, sizeof(ANGifColor) * _totalAlloced); 52 | } 53 | } 54 | 55 | - (ANGifColor)colorAtIndex:(NSUInteger)index { 56 | if (index >= _entryCount) { 57 | @throw [NSException exceptionWithName:ANGifColorIndexOutOfBoundsException 58 | reason:@"The specified color index is beyond the bounds of the array." 59 | userInfo:nil]; 60 | } 61 | return _colors[index]; 62 | } 63 | 64 | #pragma mark Averaging 65 | 66 | - (void)sortByBrightness { 67 | qsort(_colors, _entryCount, sizeof(ANGifColor), CompareColorQSort); 68 | } 69 | 70 | - (ANMutableColorArray *)colorArrayByAveragingSplit:(NSUInteger)numColors { 71 | ANMutableColorArray * newArray = [[ANMutableColorArray alloc] init]; 72 | 73 | // calculate number of colors per sector 74 | NSUInteger colorsPerSect = _entryCount / numColors; 75 | NSUInteger colorsRemaining = _entryCount % numColors; 76 | NSUInteger startIndex = 0; 77 | 78 | for (NSUInteger i = 0; i < numColors; i++) { 79 | NSUInteger size = colorsPerSect; 80 | if (colorsRemaining > 0) { 81 | size += 1; 82 | colorsRemaining--; 83 | } 84 | 85 | if (size == 0) break; 86 | 87 | double red = 0, green = 0, blue = 0; 88 | 89 | // average colors 90 | for (NSUInteger j = startIndex; j < startIndex + size; j++) { 91 | ANGifColor aColor = _colors[j]; 92 | red += (double)aColor.red; 93 | green += (double)aColor.green; 94 | blue += (double)aColor.blue; 95 | } 96 | 97 | red /= (double)size; 98 | green /= (double)size; 99 | blue /= (double)size; 100 | 101 | ANGifColor genColor = ANGifColorMake((UInt8)red, (UInt8)green, (UInt8)blue); 102 | [newArray addColor:genColor]; 103 | 104 | startIndex += size; 105 | } 106 | #if __has_feature(objc_arc) 107 | return newArray; 108 | #else 109 | return [newArray autorelease]; 110 | #endif 111 | } 112 | 113 | - (void)removeDuplicates { 114 | return; 115 | for (NSUInteger i = 0; i < _entryCount; i++) { 116 | ANGifColor currentColor = _colors[i]; 117 | for (NSUInteger j = i + 1; j < _entryCount; j++) { 118 | ANGifColor anotherColor = _colors[j]; 119 | if (ANGifColorIsEqual(currentColor, anotherColor)) { 120 | [self removeAtIndex:j]; 121 | j--; 122 | } 123 | } 124 | } 125 | } 126 | 127 | - (ANGifColor)averagePopFirst { 128 | if (_entryCount == 1) { 129 | ANGifColor color = [self colorAtIndex:0]; 130 | [self removeAtIndex:0]; 131 | return color; 132 | } 133 | NSUInteger bestFit = 1; 134 | NSUInteger variance = 255*3; 135 | ANGifColor firstColor = [self colorAtIndex:0]; 136 | 137 | for (NSUInteger i = 1; i < _entryCount; i++) { 138 | ANGifColor color = [self colorAtIndex:i]; 139 | NSUInteger lvariance = ANGifColorVariance(firstColor, color); 140 | if (lvariance < variance) { 141 | bestFit = i; 142 | variance = lvariance; 143 | if (variance == 0) { 144 | break; 145 | } 146 | } 147 | } 148 | 149 | ANGifColor selectedColor = [self colorAtIndex:bestFit]; 150 | [self removeAtIndex:bestFit]; 151 | [self removeAtIndex:0]; 152 | return ANGifColorAverage(selectedColor, firstColor); 153 | } 154 | 155 | #pragma mark Memory Management 156 | 157 | - (void)dealloc { 158 | free(_colors); 159 | #if !__has_feature(objc_arc) 160 | [super dealloc]; 161 | #endif 162 | } 163 | 164 | @end 165 | 166 | int CompareColorQSort (const void * ent1, const void * ent2) { 167 | ANGifColor * color1 = (ANGifColor *)ent1; 168 | ANGifColor * color2 = (ANGifColor *)ent2; 169 | return ((int)(color1->red + color1->green + color1->blue) - 170 | (int)(color2->red + color2->green + color2->blue)); 171 | } 172 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifDataSubblock.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifDataSubblock.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANGifDataSubblock : NSObject { 12 | NSData * subblockData; 13 | } 14 | 15 | + (NSArray *)dataSubblocksForData:(NSData *)largeData; 16 | 17 | - (id)initWithBlockData:(NSData *)theData; 18 | - (NSData *)encodeBlock; 19 | - (void)writeToFileHandle:(NSFileHandle *)fileHandle; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifDataSubblock.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifDataSubblock.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifDataSubblock.h" 11 | 12 | @implementation ANGifDataSubblock 13 | 14 | + (NSArray *)dataSubblocksForData:(NSData *)largeData { 15 | NSMutableArray * array = [NSMutableArray array]; 16 | 17 | NSUInteger length = [largeData length]; 18 | const char * bytes = (const char *)[largeData bytes]; 19 | 20 | for (NSUInteger index = 0; index < length; index += 255) { 21 | NSUInteger blockLen = 255; 22 | if (length - index < blockLen) blockLen = length - index; 23 | 24 | NSData * theData = [NSData dataWithBytes:&bytes[index] length:blockLen]; 25 | ANGifDataSubblock * subblock = [[ANGifDataSubblock alloc] initWithBlockData:theData]; 26 | [array addObject:subblock]; 27 | #if !__has_feature(objc_arc) 28 | [subblock release]; 29 | #endif 30 | } 31 | 32 | return [NSArray arrayWithArray:array]; 33 | } 34 | 35 | - (id)initWithBlockData:(NSData *)theData { 36 | if ((self = [super init])) { 37 | #if __has_feature(objc_arc) 38 | subblockData = theData; 39 | #else 40 | subblockData = [theData retain]; 41 | #endif 42 | } 43 | return self; 44 | } 45 | 46 | - (NSData *)encodeBlock { 47 | NSMutableData * data = [NSMutableData data]; 48 | UInt8 length = (UInt8)[subblockData length]; 49 | [data appendBytes:&length length:1]; 50 | [data appendData:subblockData]; 51 | 52 | return [NSData dataWithData:data]; 53 | } 54 | 55 | - (void)writeToFileHandle:(NSFileHandle *)fileHandle { 56 | UInt8 length = (UInt8)[subblockData length]; 57 | [fileHandle writeData:[NSData dataWithBytes:&length length:1]]; 58 | [fileHandle writeData:subblockData]; 59 | } 60 | 61 | #if !__has_feature(objc_arc) 62 | 63 | - (void)dealloc { 64 | [subblockData release]; 65 | [super dealloc]; 66 | } 67 | 68 | #endif 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifImageDescriptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifImageDescriptor.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANGifImageFrame.h" 11 | 12 | #define kImageSeparator 0x2C 13 | 14 | @interface ANGifImageDescriptor : NSObject { 15 | #if __has_feature(objc_arc) 16 | __weak ANGifImageFrame * imageFrame; 17 | #else 18 | ANGifImageFrame * imageFrame; 19 | #endif 20 | } 21 | 22 | - (id)initWithImageFrame:(ANGifImageFrame *)anImage; 23 | - (NSData *)encodeBlock; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifImageDescriptor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifImageDescriptor.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifImageDescriptor.h" 11 | 12 | @implementation ANGifImageDescriptor 13 | 14 | - (id)initWithImageFrame:(ANGifImageFrame *)anImage { 15 | if ((self = [super init])) { 16 | imageFrame = anImage; 17 | } 18 | return self; 19 | } 20 | 21 | - (NSData *)encodeBlock { 22 | NSMutableData * encoded = [NSMutableData data]; 23 | 24 | UInt8 aByte = kImageSeparator; 25 | UInt16 doubleByte; 26 | 27 | [encoded appendBytes:&aByte length:1]; 28 | doubleByte = (UInt16)[imageFrame offsetX]; 29 | [encoded appendBytes:&doubleByte length:2]; 30 | doubleByte = (UInt16)[imageFrame offsetY]; 31 | [encoded appendBytes:&doubleByte length:2]; 32 | doubleByte = (UInt16)[[imageFrame pixelSource] pixelsWide]; 33 | [encoded appendBytes:&doubleByte length:2]; 34 | doubleByte = (UInt16)[[imageFrame pixelSource] pixelsHigh]; 35 | [encoded appendBytes:&doubleByte length:2]; 36 | 37 | UInt8 packedInfo = 0; 38 | if ([imageFrame localColorTable]) { 39 | UInt8 lctSize = [[imageFrame localColorTable] colorTableSizeValue]; 40 | packedInfo |= 128; 41 | packedInfo |= lctSize; 42 | // packedInfo |= (1 << 3); // sort flag 43 | } 44 | [encoded appendBytes:&packedInfo length:1]; 45 | 46 | return [NSData dataWithData:encoded]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifImageFrame.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifImageFrame.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANColorTable.h" 11 | #import "ANGifImageFramePixelSource.h" 12 | 13 | @interface ANGifImageFrame : NSObject { 14 | id pixelSource; 15 | ANColorTable * localColorTable; 16 | UInt16 offsetX; 17 | UInt16 offsetY; 18 | NSTimeInterval delayTime; 19 | } 20 | 21 | @property (nonatomic, retain) id pixelSource; 22 | @property (nonatomic, retain) ANColorTable * localColorTable; 23 | @property (readwrite) UInt16 offsetX, offsetY; 24 | @property (readwrite) NSTimeInterval delayTime; 25 | 26 | /** 27 | * Create an ANGifImageFrame with an image source, a local color table (should be empty), and a delay. 28 | * @param aSource A non-nil pixel data source from which image data will come. 29 | * @param table The local color table that will be used by this image. If this is nil, the global color table 30 | * will be used for this image. 31 | * @param delay The delay in seconds before the next frame will be shown. This is accurate to the millisecond. 32 | */ 33 | - (id)initWithPixelSource:(id)aSource colorTable:(ANColorTable *)table delayTime:(NSTimeInterval)delay; 34 | 35 | /** 36 | * Create an ANGifImageFrame with an image source and a delay. 37 | * @param aSource A non-nil pixel data source from which image data will come. 38 | * @param delay The delay in seconds before the next frame will be shown. This is accurate to the millisecond. 39 | * @discussion Despite the fact that no color table was provided, the encoder may chose to use 40 | * a local color table if no global color table has been created. 41 | */ 42 | - (id)initWithPixelSource:(id)aSource delayTime:(NSTimeInterval)delay; 43 | 44 | /** 45 | * Encodes each pixel using the specified color table, adding colors as it goes along. 46 | * @param colorTable Either a local color table or a global color table. This will be mutated 47 | * only by calling the addColor: method. This may not be nil. 48 | * @return The encoded data of the image, or nil upon error. 49 | */ 50 | - (NSData *)encodeImageUsingColorTable:(ANColorTable *)colorTable; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifImageFrame.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANGifImageFrame.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANGifImageFrame.h" 11 | 12 | @implementation ANGifImageFrame 13 | 14 | @synthesize pixelSource; 15 | @synthesize localColorTable; 16 | @synthesize offsetX, offsetY; 17 | @synthesize delayTime; 18 | 19 | - (id)initWithPixelSource:(id)aSource colorTable:(ANColorTable *)table delayTime:(NSTimeInterval)delay { 20 | if ((self = [super init])) { 21 | self.pixelSource = aSource; 22 | self.localColorTable = table; 23 | self.delayTime = delay; 24 | } 25 | return self; 26 | } 27 | 28 | - (id)initWithPixelSource:(id)aSource delayTime:(NSTimeInterval)delay { 29 | self = [self initWithPixelSource:aSource 30 | colorTable:nil delayTime:delay]; 31 | return self; 32 | } 33 | 34 | - (NSData *)encodeImageUsingColorTable:(ANColorTable *)colorTable { 35 | NSUInteger color[4]; 36 | ANGifColor gifColor; 37 | NSMutableData * encodedData = [NSMutableData data]; 38 | NSUInteger width = [pixelSource pixelsWide]; 39 | NSUInteger height = [pixelSource pixelsHigh]; 40 | 41 | for (NSUInteger y = 0; y < height; y++) { 42 | for (NSUInteger x = 0; x < width; x++) { 43 | UInt8 myByte; 44 | [pixelSource getPixel:color atX:x y:y]; 45 | if ([colorTable hasTransparentFirst] && color[3] < 0x20 && [pixelSource hasTransparency]) { 46 | myByte = [colorTable transparentIndex]; 47 | [encodedData appendBytes:&myByte length:1]; 48 | } else { 49 | gifColor.red = color[0]; 50 | gifColor.green = color[1]; 51 | gifColor.blue = color[2]; 52 | myByte = [colorTable addColor:gifColor]; 53 | [encodedData appendBytes:&myByte length:1]; 54 | } 55 | } 56 | } 57 | 58 | return [NSData dataWithData:encodedData]; // return immutable version 59 | } 60 | 61 | #if !__has_feature(objc_arc) 62 | 63 | - (void)dealloc { 64 | self.pixelSource = nil; 65 | self.localColorTable = nil; 66 | [super dealloc]; 67 | } 68 | 69 | #endif 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /ANGif/ImageFrame/ANGifImageFramePixelSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // PixelSource.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol ANGifImageFramePixelSource 12 | 13 | - (NSUInteger)pixelsWide; 14 | - (NSUInteger)pixelsHigh; 15 | - (void)getPixel:(NSUInteger *)pixel atX:(NSInteger)x y:(NSInteger)y; 16 | - (BOOL)hasTransparency; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ANGif/LZW/LZWBuffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // LZWBuffer.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/20/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #ifndef GifPro_LZWBuffer_h 10 | #define GifPro_LZWBuffer_h 11 | 12 | #define LZWBufferSize 0x1000 13 | 14 | struct _LZWBuffer { 15 | UInt8 * _bytePool; 16 | NSUInteger _totalSize; 17 | NSUInteger numBits; 18 | }; 19 | 20 | typedef struct _LZWBuffer *LZWBufferRef; 21 | 22 | LZWBufferRef lzwbuffer_create (void); 23 | LZWBufferRef lzwbuffer_create_data (const UInt8 * bytes, NSUInteger length); 24 | 25 | void lzwbuffer_add_bit (LZWBufferRef buffer, BOOL flag); 26 | BOOL lzwbuffer_get_bit (LZWBufferRef buffer, NSUInteger bitIndex); 27 | 28 | NSUInteger lzwbuffer_bytes_used (LZWBufferRef buffer); 29 | 30 | void lzwbuffer_free (LZWBufferRef buffer); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /ANGif/LZW/LZWBuffer.m: -------------------------------------------------------------------------------- 1 | // 2 | // LZWBuffer.c 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/20/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #include "LZWBuffer.h" 10 | 11 | LZWBufferRef lzwbuffer_create (void) { 12 | LZWBufferRef buffer = (LZWBufferRef)malloc(sizeof(struct _LZWBuffer)); 13 | buffer->numBits = 0; 14 | buffer->_totalSize = LZWBufferSize; 15 | buffer->_bytePool = (UInt8 *)malloc(LZWBufferSize); 16 | return buffer; 17 | } 18 | 19 | LZWBufferRef lzwbuffer_create_data (const UInt8 * bytes, NSUInteger length) { 20 | LZWBufferRef buffer = (LZWBufferRef)malloc(sizeof(struct _LZWBuffer)); 21 | buffer->numBits = length * 8; 22 | buffer->_totalSize = length; 23 | buffer->_bytePool = (UInt8 *)malloc(length); 24 | memcpy(buffer->_bytePool, bytes, length); 25 | return buffer; 26 | } 27 | 28 | void lzwbuffer_add_bit (LZWBufferRef buffer, BOOL flag) { 29 | NSUInteger endNumber = buffer->numBits + 1; 30 | if (endNumber / 8 + (endNumber % 8 == 0 ? 0 : 1) > buffer->_totalSize) { 31 | buffer->_totalSize += LZWBufferSize; 32 | buffer->_bytePool = (UInt8 *)realloc(buffer->_bytePool, buffer->_totalSize); 33 | } 34 | NSUInteger byteIndex = (buffer->numBits) / 8; 35 | UInt8 byteMask = (1 << ((buffer->numBits) % 8)); 36 | if (flag) { 37 | (buffer->_bytePool)[byteIndex] |= byteMask; 38 | } else { 39 | (buffer->_bytePool)[byteIndex] &= (0xff ^ byteMask); 40 | } 41 | buffer->numBits += 1; 42 | } 43 | 44 | BOOL lzwbuffer_get_bit (LZWBufferRef buffer, NSUInteger bitIndex) { 45 | NSUInteger byteIndex = bitIndex / 8; 46 | UInt8 byteMask = (1 << (bitIndex % 8)); 47 | return (((buffer->_bytePool[byteIndex] & byteMask) == 0) ? NO : YES); 48 | } 49 | 50 | NSUInteger lzwbuffer_bytes_used (LZWBufferRef buffer) { 51 | NSUInteger numBytes = buffer->numBits / 8 + (buffer->numBits % 8 == 0 ? 0 : 1); 52 | return numBytes; 53 | } 54 | 55 | void lzwbuffer_free (LZWBufferRef buffer) { 56 | free(buffer->_bytePool); 57 | free(buffer); 58 | } 59 | -------------------------------------------------------------------------------- /ANGif/LZW/LZWSpoof.h: -------------------------------------------------------------------------------- 1 | // 2 | // LZWSpoof.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #include "LZWBuffer.h" 11 | 12 | #define BitOutOfRangeException @"BitOutOfRangeException" 13 | 14 | void LZWDataAddBit (UInt8 ** _bytePool, NSUInteger * _totalSize, NSUInteger * numBits, BOOL flag); 15 | BOOL LZWDataGetBit (UInt8 * _bytePool, NSUInteger bitIndex); 16 | 17 | @interface LZWSpoof : NSObject { 18 | LZWBufferRef buffer; 19 | } 20 | 21 | @property (readonly) LZWBufferRef buffer; 22 | 23 | + (NSData *)lzwExpandData:(NSData *)existingData; 24 | 25 | - (id)initWithData:(NSData *)initialData; 26 | - (NSData *)convertToData; 27 | 28 | - (void)addLZWClearCode; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /ANGif/LZW/LZWSpoof.m: -------------------------------------------------------------------------------- 1 | // 2 | // LZWSpoof.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "LZWSpoof.h" 11 | 12 | @implementation LZWSpoof 13 | 14 | @synthesize buffer; 15 | 16 | #pragma mark LZW 17 | 18 | + (NSData *)lzwExpandData:(NSData *)existingData { 19 | LZWSpoof * destinationBuffer = [[LZWSpoof alloc] init]; 20 | LZWSpoof * existingBuffer = [[LZWSpoof alloc] initWithData:existingData]; 21 | 22 | LZWBufferRef sourceBuff = [existingBuffer buffer]; 23 | LZWBufferRef destBuff = [destinationBuffer buffer]; 24 | 25 | NSUInteger clearCodeCount = 254; 26 | [destinationBuffer addLZWClearCode]; 27 | // loop through every byte, write it, and then write a clear code. 28 | for (NSUInteger byteIndex = 0; byteIndex < [existingData length]; byteIndex++) { 29 | NSUInteger startBit = byteIndex * 8; 30 | for (NSUInteger bitIndex = startBit; bitIndex < startBit + 8; bitIndex++) { 31 | lzwbuffer_add_bit(destBuff, lzwbuffer_get_bit(sourceBuff, bitIndex)); 32 | } 33 | lzwbuffer_add_bit(destBuff, NO); 34 | // add clear code if needed 35 | clearCodeCount--; 36 | if (clearCodeCount == 0) { 37 | [destinationBuffer addLZWClearCode]; 38 | clearCodeCount = 254; 39 | } 40 | } 41 | 42 | // LZW "STOP" directive 43 | lzwbuffer_add_bit(destBuff, YES); 44 | for (int i = 0; i < 7; i++) { 45 | lzwbuffer_add_bit(destBuff, NO); 46 | } 47 | lzwbuffer_add_bit(destBuff, YES); 48 | 49 | #if !__has_feature(objc_arc) 50 | [existingBuffer release]; 51 | NSData * theData = [destinationBuffer convertToData]; 52 | [destinationBuffer release]; 53 | return theData; 54 | #else 55 | return [destinationBuffer convertToData]; 56 | #endif 57 | } 58 | 59 | #pragma mark Bit Buffer 60 | 61 | - (id)initWithData:(NSData *)initialData { 62 | if ((self = [super init])) { 63 | buffer = lzwbuffer_create_data((const UInt8 *)[initialData bytes], [initialData length]); 64 | } 65 | return self; 66 | } 67 | 68 | - (id)init { 69 | if ((self = [super init])) { 70 | buffer = lzwbuffer_create(); 71 | } 72 | return self; 73 | } 74 | 75 | #pragma mark LZW Buffer 76 | 77 | - (void)addLZWClearCode { 78 | for (int i = 0; i < 8; i++) { 79 | lzwbuffer_add_bit(buffer, NO); 80 | } 81 | lzwbuffer_add_bit(buffer, YES); 82 | } 83 | 84 | #pragma mark Data 85 | 86 | - (NSData *)convertToData { 87 | NSUInteger numBytes = lzwbuffer_bytes_used(buffer); 88 | return [NSData dataWithBytes:buffer->_bytePool length:numBytes]; 89 | } 90 | 91 | - (void)dealloc { 92 | lzwbuffer_free(buffer); 93 | #if !__has_feature(objc_arc) 94 | [super dealloc]; 95 | #endif 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /ANNSImageGifPixelSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANNSImageGifPixelSource.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANGifImageFrame.h" 11 | 12 | @interface ANNSImageGifPixelSource : NSObject { 13 | NSBitmapImageRep * bitmapRep; 14 | } 15 | 16 | - (id)initWithImage:(NSImage *)anImage; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ANNSImageGifPixelSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANNSImageGifPixelSource.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/2/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANNSImageGifPixelSource.h" 11 | 12 | @implementation ANNSImageGifPixelSource 13 | 14 | - (id)initWithImage:(NSImage *)anImage { 15 | if ((self = [super init])) { 16 | bitmapRep = [[NSBitmapImageRep alloc] initWithData:[anImage TIFFRepresentation]]; 17 | bitmapRep.size = NSMakeSize([bitmapRep pixelsWide], [bitmapRep pixelsHigh]); 18 | } 19 | return self; 20 | } 21 | 22 | - (NSUInteger)pixelsWide { 23 | return [bitmapRep pixelsWide]; 24 | } 25 | 26 | - (NSUInteger)pixelsHigh { 27 | return [bitmapRep pixelsHigh]; 28 | } 29 | 30 | - (void)getPixel:(NSUInteger *)pixel atX:(NSInteger)x y:(NSInteger)y { 31 | [bitmapRep getPixel:pixel atX:x y:y]; 32 | } 33 | 34 | - (BOOL)hasTransparency { 35 | return [bitmapRep hasAlpha]; 36 | } 37 | 38 | #if !__has_feature(objc_arc) 39 | - (void)dealloc { 40 | [bitmapRep release]; 41 | [super dealloc]; 42 | } 43 | #endif 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /GifPro.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FA0A5C121461F7C6006BEE0C /* ANNSImageGifPixelSource.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0A5C111461F7C6006BEE0C /* ANNSImageGifPixelSource.m */; }; 11 | FA0B00A31460A8F100E57109 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA0B00A21460A8F100E57109 /* Cocoa.framework */; }; 12 | FA0B00AD1460A8F100E57109 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA0B00AB1460A8F100E57109 /* InfoPlist.strings */; }; 13 | FA0B00AF1460A8F100E57109 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0B00AE1460A8F100E57109 /* main.m */; }; 14 | FA0B00B31460A8F100E57109 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = FA0B00B11460A8F100E57109 /* Credits.rtf */; }; 15 | FA0B00B61460A8F100E57109 /* ANAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0B00B51460A8F100E57109 /* ANAppDelegate.m */; }; 16 | FA0B00B91460A8F100E57109 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = FA0B00B71460A8F100E57109 /* MainMenu.xib */; }; 17 | FA0C099B14636ECB0074409F /* ANImageListEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C099A14636ECB0074409F /* ANImageListEntry.m */; }; 18 | FA0C099E146370F40074409F /* ANExportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C099D146370F40074409F /* ANExportWindow.m */; }; 19 | FA0C09CD146388170074409F /* ANGifEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09AE146388170074409F /* ANGifEncoder.m */; }; 20 | FA0C09CE146388170074409F /* ANGifGraphicControlExt.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09B0146388170074409F /* ANGifGraphicControlExt.m */; }; 21 | FA0C09CF146388170074409F /* ANGifLogicalScreenDesc.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09B2146388170074409F /* ANGifLogicalScreenDesc.m */; }; 22 | FA0C09D0146388170074409F /* ANGifAppExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09B5146388170074409F /* ANGifAppExtension.m */; }; 23 | FA0C09D1146388170074409F /* ANGifNetscapeAppExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09B7146388170074409F /* ANGifNetscapeAppExtension.m */; }; 24 | FA0C09D2146388170074409F /* ANAvgColorTable.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09BA146388170074409F /* ANAvgColorTable.m */; }; 25 | FA0C09D3146388170074409F /* ANColorTable.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09BC146388170074409F /* ANColorTable.m */; }; 26 | FA0C09D4146388170074409F /* ANCutColorTable.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09BF146388170074409F /* ANCutColorTable.m */; }; 27 | FA0C09D5146388170074409F /* ANMutableColorArray.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09C1146388170074409F /* ANMutableColorArray.m */; }; 28 | FA0C09D6146388170074409F /* ANGifDataSubblock.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09C4146388170074409F /* ANGifDataSubblock.m */; }; 29 | FA0C09D7146388170074409F /* ANGifImageDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09C6146388170074409F /* ANGifImageDescriptor.m */; }; 30 | FA0C09D8146388170074409F /* ANGifImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09C8146388170074409F /* ANGifImageFrame.m */; }; 31 | FA0C09D9146388170074409F /* LZWSpoof.m in Sources */ = {isa = PBXBuildFile; fileRef = FA0C09CC146388170074409F /* LZWSpoof.m */; }; 32 | FA3E7C7D1479A30A00EE7144 /* LZWBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = FA3E7C7C1479A30A00EE7144 /* LZWBuffer.m */; }; 33 | FA9B338E1464812700D58B3A /* NSImage+Resize.m in Sources */ = {isa = PBXBuildFile; fileRef = FA9B338D1464812700D58B3A /* NSImage+Resize.m */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | FA0A5C101461F7C5006BEE0C /* ANNSImageGifPixelSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ANNSImageGifPixelSource.h; path = ../ANNSImageGifPixelSource.h; sourceTree = ""; }; 38 | FA0A5C111461F7C6006BEE0C /* ANNSImageGifPixelSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ANNSImageGifPixelSource.m; path = ../ANNSImageGifPixelSource.m; sourceTree = ""; }; 39 | FA0B009E1460A8F100E57109 /* GifPro.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GifPro.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | FA0B00A21460A8F100E57109 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 41 | FA0B00A51460A8F100E57109 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 42 | FA0B00A61460A8F100E57109 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 43 | FA0B00A71460A8F100E57109 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 44 | FA0B00AA1460A8F100E57109 /* GifPro-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GifPro-Info.plist"; sourceTree = ""; }; 45 | FA0B00AC1460A8F100E57109 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | FA0B00AE1460A8F100E57109 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | FA0B00B01460A8F100E57109 /* GifPro-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GifPro-Prefix.pch"; sourceTree = ""; }; 48 | FA0B00B21460A8F100E57109 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 49 | FA0B00B41460A8F100E57109 /* ANAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ANAppDelegate.h; sourceTree = ""; }; 50 | FA0B00B51460A8F100E57109 /* ANAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ANAppDelegate.m; sourceTree = ""; }; 51 | FA0B00B81460A8F100E57109 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 52 | FA0C099914636ECB0074409F /* ANImageListEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANImageListEntry.h; sourceTree = ""; }; 53 | FA0C099A14636ECB0074409F /* ANImageListEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANImageListEntry.m; sourceTree = ""; }; 54 | FA0C099C146370F40074409F /* ANExportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANExportWindow.h; sourceTree = ""; }; 55 | FA0C099D146370F40074409F /* ANExportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ANExportWindow.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 56 | FA0C09AD146388170074409F /* ANGifEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifEncoder.h; sourceTree = ""; }; 57 | FA0C09AE146388170074409F /* ANGifEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifEncoder.m; sourceTree = ""; }; 58 | FA0C09AF146388170074409F /* ANGifGraphicControlExt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifGraphicControlExt.h; sourceTree = ""; }; 59 | FA0C09B0146388170074409F /* ANGifGraphicControlExt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifGraphicControlExt.m; sourceTree = ""; }; 60 | FA0C09B1146388170074409F /* ANGifLogicalScreenDesc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifLogicalScreenDesc.h; sourceTree = ""; }; 61 | FA0C09B2146388170074409F /* ANGifLogicalScreenDesc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifLogicalScreenDesc.m; sourceTree = ""; }; 62 | FA0C09B4146388170074409F /* ANGifAppExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifAppExtension.h; sourceTree = ""; }; 63 | FA0C09B5146388170074409F /* ANGifAppExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifAppExtension.m; sourceTree = ""; }; 64 | FA0C09B6146388170074409F /* ANGifNetscapeAppExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifNetscapeAppExtension.h; sourceTree = ""; }; 65 | FA0C09B7146388170074409F /* ANGifNetscapeAppExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifNetscapeAppExtension.m; sourceTree = ""; }; 66 | FA0C09B9146388170074409F /* ANAvgColorTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANAvgColorTable.h; sourceTree = ""; }; 67 | FA0C09BA146388170074409F /* ANAvgColorTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANAvgColorTable.m; sourceTree = ""; }; 68 | FA0C09BB146388170074409F /* ANColorTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANColorTable.h; sourceTree = ""; }; 69 | FA0C09BC146388170074409F /* ANColorTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANColorTable.m; sourceTree = ""; }; 70 | FA0C09BE146388170074409F /* ANCutColorTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANCutColorTable.h; sourceTree = ""; }; 71 | FA0C09BF146388170074409F /* ANCutColorTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANCutColorTable.m; sourceTree = ""; }; 72 | FA0C09C0146388170074409F /* ANMutableColorArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANMutableColorArray.h; sourceTree = ""; }; 73 | FA0C09C1146388170074409F /* ANMutableColorArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANMutableColorArray.m; sourceTree = ""; }; 74 | FA0C09C3146388170074409F /* ANGifDataSubblock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifDataSubblock.h; sourceTree = ""; }; 75 | FA0C09C4146388170074409F /* ANGifDataSubblock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifDataSubblock.m; sourceTree = ""; }; 76 | FA0C09C5146388170074409F /* ANGifImageDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifImageDescriptor.h; sourceTree = ""; }; 77 | FA0C09C6146388170074409F /* ANGifImageDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifImageDescriptor.m; sourceTree = ""; }; 78 | FA0C09C7146388170074409F /* ANGifImageFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifImageFrame.h; sourceTree = ""; }; 79 | FA0C09C8146388170074409F /* ANGifImageFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ANGifImageFrame.m; sourceTree = ""; }; 80 | FA0C09C9146388170074409F /* ANGifImageFramePixelSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ANGifImageFramePixelSource.h; sourceTree = ""; }; 81 | FA0C09CB146388170074409F /* LZWSpoof.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LZWSpoof.h; sourceTree = ""; }; 82 | FA0C09CC146388170074409F /* LZWSpoof.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LZWSpoof.m; sourceTree = ""; }; 83 | FA3E7C7C1479A30A00EE7144 /* LZWBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LZWBuffer.m; sourceTree = ""; }; 84 | FA3E7C7F1479A31400EE7144 /* LZWBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LZWBuffer.h; sourceTree = ""; }; 85 | FA9B338C1464812700D58B3A /* NSImage+Resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+Resize.h"; sourceTree = ""; }; 86 | FA9B338D1464812700D58B3A /* NSImage+Resize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+Resize.m"; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | FA0B009B1460A8F100E57109 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | FA0B00A31460A8F100E57109 /* Cocoa.framework in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | FA0B00931460A8F100E57109 = { 102 | isa = PBXGroup; 103 | children = ( 104 | FA0C09AC146388170074409F /* ANGif */, 105 | FA0B00A81460A8F100E57109 /* GifPro */, 106 | FA0B00A11460A8F100E57109 /* Frameworks */, 107 | FA0B009F1460A8F100E57109 /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | FA0B009F1460A8F100E57109 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | FA0B009E1460A8F100E57109 /* GifPro.app */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | FA0B00A11460A8F100E57109 /* Frameworks */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | FA0B00A21460A8F100E57109 /* Cocoa.framework */, 123 | FA0B00A41460A8F100E57109 /* Other Frameworks */, 124 | ); 125 | name = Frameworks; 126 | sourceTree = ""; 127 | }; 128 | FA0B00A41460A8F100E57109 /* Other Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | FA0B00A51460A8F100E57109 /* AppKit.framework */, 132 | FA0B00A61460A8F100E57109 /* CoreData.framework */, 133 | FA0B00A71460A8F100E57109 /* Foundation.framework */, 134 | ); 135 | name = "Other Frameworks"; 136 | sourceTree = ""; 137 | }; 138 | FA0B00A81460A8F100E57109 /* GifPro */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | FA9B338A1464810C00D58B3A /* NSImage Stuff */, 142 | FA0B00B41460A8F100E57109 /* ANAppDelegate.h */, 143 | FA0B00B51460A8F100E57109 /* ANAppDelegate.m */, 144 | FA0C099914636ECB0074409F /* ANImageListEntry.h */, 145 | FA0C099A14636ECB0074409F /* ANImageListEntry.m */, 146 | FA0C099C146370F40074409F /* ANExportWindow.h */, 147 | FA0C099D146370F40074409F /* ANExportWindow.m */, 148 | FA0B00B71460A8F100E57109 /* MainMenu.xib */, 149 | FA0B00A91460A8F100E57109 /* Supporting Files */, 150 | ); 151 | path = GifPro; 152 | sourceTree = ""; 153 | }; 154 | FA0B00A91460A8F100E57109 /* Supporting Files */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | FA0B00AA1460A8F100E57109 /* GifPro-Info.plist */, 158 | FA0B00AB1460A8F100E57109 /* InfoPlist.strings */, 159 | FA0B00AE1460A8F100E57109 /* main.m */, 160 | FA0B00B01460A8F100E57109 /* GifPro-Prefix.pch */, 161 | FA0B00B11460A8F100E57109 /* Credits.rtf */, 162 | ); 163 | name = "Supporting Files"; 164 | sourceTree = ""; 165 | }; 166 | FA0C09AC146388170074409F /* ANGif */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | FA0C09B3146388170074409F /* App Extensions */, 170 | FA0C09B8146388170074409F /* ColorTable */, 171 | FA0C09C2146388170074409F /* ImageFrame */, 172 | FA0C09CA146388170074409F /* LZW */, 173 | FA0C09AD146388170074409F /* ANGifEncoder.h */, 174 | FA0C09AE146388170074409F /* ANGifEncoder.m */, 175 | FA0C09AF146388170074409F /* ANGifGraphicControlExt.h */, 176 | FA0C09B0146388170074409F /* ANGifGraphicControlExt.m */, 177 | FA0C09B1146388170074409F /* ANGifLogicalScreenDesc.h */, 178 | FA0C09B2146388170074409F /* ANGifLogicalScreenDesc.m */, 179 | ); 180 | path = ANGif; 181 | sourceTree = ""; 182 | }; 183 | FA0C09B3146388170074409F /* App Extensions */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | FA0C09B4146388170074409F /* ANGifAppExtension.h */, 187 | FA0C09B5146388170074409F /* ANGifAppExtension.m */, 188 | FA0C09B6146388170074409F /* ANGifNetscapeAppExtension.h */, 189 | FA0C09B7146388170074409F /* ANGifNetscapeAppExtension.m */, 190 | ); 191 | path = "App Extensions"; 192 | sourceTree = ""; 193 | }; 194 | FA0C09B8146388170074409F /* ColorTable */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | FA0C09BB146388170074409F /* ANColorTable.h */, 198 | FA0C09BC146388170074409F /* ANColorTable.m */, 199 | FA0C09B9146388170074409F /* ANAvgColorTable.h */, 200 | FA0C09BA146388170074409F /* ANAvgColorTable.m */, 201 | FA0C09BD146388170074409F /* Cut */, 202 | ); 203 | path = ColorTable; 204 | sourceTree = ""; 205 | }; 206 | FA0C09BD146388170074409F /* Cut */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | FA0C09BE146388170074409F /* ANCutColorTable.h */, 210 | FA0C09BF146388170074409F /* ANCutColorTable.m */, 211 | FA0C09C0146388170074409F /* ANMutableColorArray.h */, 212 | FA0C09C1146388170074409F /* ANMutableColorArray.m */, 213 | ); 214 | path = Cut; 215 | sourceTree = ""; 216 | }; 217 | FA0C09C2146388170074409F /* ImageFrame */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | FA0C09C3146388170074409F /* ANGifDataSubblock.h */, 221 | FA0C09C4146388170074409F /* ANGifDataSubblock.m */, 222 | FA0C09C5146388170074409F /* ANGifImageDescriptor.h */, 223 | FA0C09C6146388170074409F /* ANGifImageDescriptor.m */, 224 | FA0C09C7146388170074409F /* ANGifImageFrame.h */, 225 | FA0C09C8146388170074409F /* ANGifImageFrame.m */, 226 | FA0C09C9146388170074409F /* ANGifImageFramePixelSource.h */, 227 | ); 228 | path = ImageFrame; 229 | sourceTree = ""; 230 | }; 231 | FA0C09CA146388170074409F /* LZW */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | FA0C09CB146388170074409F /* LZWSpoof.h */, 235 | FA0C09CC146388170074409F /* LZWSpoof.m */, 236 | FA3E7C7F1479A31400EE7144 /* LZWBuffer.h */, 237 | FA3E7C7C1479A30A00EE7144 /* LZWBuffer.m */, 238 | ); 239 | path = LZW; 240 | sourceTree = ""; 241 | }; 242 | FA9B338A1464810C00D58B3A /* NSImage Stuff */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | FA0A5C101461F7C5006BEE0C /* ANNSImageGifPixelSource.h */, 246 | FA0A5C111461F7C6006BEE0C /* ANNSImageGifPixelSource.m */, 247 | FA9B338C1464812700D58B3A /* NSImage+Resize.h */, 248 | FA9B338D1464812700D58B3A /* NSImage+Resize.m */, 249 | ); 250 | name = "NSImage Stuff"; 251 | sourceTree = ""; 252 | }; 253 | /* End PBXGroup section */ 254 | 255 | /* Begin PBXNativeTarget section */ 256 | FA0B009D1460A8F100E57109 /* GifPro */ = { 257 | isa = PBXNativeTarget; 258 | buildConfigurationList = FA0B00BC1460A8F100E57109 /* Build configuration list for PBXNativeTarget "GifPro" */; 259 | buildPhases = ( 260 | FA0B009A1460A8F100E57109 /* Sources */, 261 | FA0B009B1460A8F100E57109 /* Frameworks */, 262 | FA0B009C1460A8F100E57109 /* Resources */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | ); 268 | name = GifPro; 269 | productName = GifPro; 270 | productReference = FA0B009E1460A8F100E57109 /* GifPro.app */; 271 | productType = "com.apple.product-type.application"; 272 | }; 273 | /* End PBXNativeTarget section */ 274 | 275 | /* Begin PBXProject section */ 276 | FA0B00951460A8F100E57109 /* Project object */ = { 277 | isa = PBXProject; 278 | attributes = { 279 | LastUpgradeCheck = 0420; 280 | }; 281 | buildConfigurationList = FA0B00981460A8F100E57109 /* Build configuration list for PBXProject "GifPro" */; 282 | compatibilityVersion = "Xcode 3.2"; 283 | developmentRegion = English; 284 | hasScannedForEncodings = 0; 285 | knownRegions = ( 286 | en, 287 | ); 288 | mainGroup = FA0B00931460A8F100E57109; 289 | productRefGroup = FA0B009F1460A8F100E57109 /* Products */; 290 | projectDirPath = ""; 291 | projectRoot = ""; 292 | targets = ( 293 | FA0B009D1460A8F100E57109 /* GifPro */, 294 | ); 295 | }; 296 | /* End PBXProject section */ 297 | 298 | /* Begin PBXResourcesBuildPhase section */ 299 | FA0B009C1460A8F100E57109 /* Resources */ = { 300 | isa = PBXResourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | FA0B00AD1460A8F100E57109 /* InfoPlist.strings in Resources */, 304 | FA0B00B31460A8F100E57109 /* Credits.rtf in Resources */, 305 | FA0B00B91460A8F100E57109 /* MainMenu.xib in Resources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXResourcesBuildPhase section */ 310 | 311 | /* Begin PBXSourcesBuildPhase section */ 312 | FA0B009A1460A8F100E57109 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | FA0B00AF1460A8F100E57109 /* main.m in Sources */, 317 | FA0B00B61460A8F100E57109 /* ANAppDelegate.m in Sources */, 318 | FA0A5C121461F7C6006BEE0C /* ANNSImageGifPixelSource.m in Sources */, 319 | FA0C099B14636ECB0074409F /* ANImageListEntry.m in Sources */, 320 | FA0C099E146370F40074409F /* ANExportWindow.m in Sources */, 321 | FA0C09CD146388170074409F /* ANGifEncoder.m in Sources */, 322 | FA0C09CE146388170074409F /* ANGifGraphicControlExt.m in Sources */, 323 | FA0C09CF146388170074409F /* ANGifLogicalScreenDesc.m in Sources */, 324 | FA0C09D0146388170074409F /* ANGifAppExtension.m in Sources */, 325 | FA0C09D1146388170074409F /* ANGifNetscapeAppExtension.m in Sources */, 326 | FA0C09D2146388170074409F /* ANAvgColorTable.m in Sources */, 327 | FA0C09D3146388170074409F /* ANColorTable.m in Sources */, 328 | FA0C09D4146388170074409F /* ANCutColorTable.m in Sources */, 329 | FA0C09D5146388170074409F /* ANMutableColorArray.m in Sources */, 330 | FA0C09D6146388170074409F /* ANGifDataSubblock.m in Sources */, 331 | FA0C09D7146388170074409F /* ANGifImageDescriptor.m in Sources */, 332 | FA0C09D8146388170074409F /* ANGifImageFrame.m in Sources */, 333 | FA0C09D9146388170074409F /* LZWSpoof.m in Sources */, 334 | FA9B338E1464812700D58B3A /* NSImage+Resize.m in Sources */, 335 | FA3E7C7D1479A30A00EE7144 /* LZWBuffer.m in Sources */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | /* End PBXSourcesBuildPhase section */ 340 | 341 | /* Begin PBXVariantGroup section */ 342 | FA0B00AB1460A8F100E57109 /* InfoPlist.strings */ = { 343 | isa = PBXVariantGroup; 344 | children = ( 345 | FA0B00AC1460A8F100E57109 /* en */, 346 | ); 347 | name = InfoPlist.strings; 348 | sourceTree = ""; 349 | }; 350 | FA0B00B11460A8F100E57109 /* Credits.rtf */ = { 351 | isa = PBXVariantGroup; 352 | children = ( 353 | FA0B00B21460A8F100E57109 /* en */, 354 | ); 355 | name = Credits.rtf; 356 | sourceTree = ""; 357 | }; 358 | FA0B00B71460A8F100E57109 /* MainMenu.xib */ = { 359 | isa = PBXVariantGroup; 360 | children = ( 361 | FA0B00B81460A8F100E57109 /* en */, 362 | ); 363 | name = MainMenu.xib; 364 | sourceTree = ""; 365 | }; 366 | /* End PBXVariantGroup section */ 367 | 368 | /* Begin XCBuildConfiguration section */ 369 | FA0B00BA1460A8F100E57109 /* Debug */ = { 370 | isa = XCBuildConfiguration; 371 | buildSettings = { 372 | ALWAYS_SEARCH_USER_PATHS = NO; 373 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 374 | CLANG_ENABLE_OBJC_ARC = YES; 375 | COPY_PHASE_STRIP = NO; 376 | GCC_C_LANGUAGE_STANDARD = gnu99; 377 | GCC_DYNAMIC_NO_PIC = NO; 378 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 379 | GCC_OPTIMIZATION_LEVEL = 0; 380 | GCC_PREPROCESSOR_DEFINITIONS = ( 381 | "DEBUG=1", 382 | "$(inherited)", 383 | ); 384 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 385 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 387 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 388 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 389 | GCC_WARN_UNUSED_VARIABLE = YES; 390 | MACOSX_DEPLOYMENT_TARGET = 10.7; 391 | ONLY_ACTIVE_ARCH = YES; 392 | SDKROOT = macosx; 393 | }; 394 | name = Debug; 395 | }; 396 | FA0B00BB1460A8F100E57109 /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ALWAYS_SEARCH_USER_PATHS = NO; 400 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 401 | CLANG_ENABLE_OBJC_ARC = YES; 402 | COPY_PHASE_STRIP = YES; 403 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 404 | GCC_C_LANGUAGE_STANDARD = gnu99; 405 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 406 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 407 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 408 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 409 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 410 | GCC_WARN_UNUSED_VARIABLE = YES; 411 | MACOSX_DEPLOYMENT_TARGET = 10.7; 412 | SDKROOT = macosx; 413 | }; 414 | name = Release; 415 | }; 416 | FA0B00BD1460A8F100E57109 /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | CLANG_ENABLE_OBJC_ARC = YES; 420 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 421 | GCC_PREFIX_HEADER = "GifPro/GifPro-Prefix.pch"; 422 | INFOPLIST_FILE = "GifPro/GifPro-Info.plist"; 423 | PRODUCT_NAME = "$(TARGET_NAME)"; 424 | WRAPPER_EXTENSION = app; 425 | }; 426 | name = Debug; 427 | }; 428 | FA0B00BE1460A8F100E57109 /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | CLANG_ENABLE_OBJC_ARC = YES; 432 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 433 | GCC_PREFIX_HEADER = "GifPro/GifPro-Prefix.pch"; 434 | INFOPLIST_FILE = "GifPro/GifPro-Info.plist"; 435 | PRODUCT_NAME = "$(TARGET_NAME)"; 436 | WRAPPER_EXTENSION = app; 437 | }; 438 | name = Release; 439 | }; 440 | /* End XCBuildConfiguration section */ 441 | 442 | /* Begin XCConfigurationList section */ 443 | FA0B00981460A8F100E57109 /* Build configuration list for PBXProject "GifPro" */ = { 444 | isa = XCConfigurationList; 445 | buildConfigurations = ( 446 | FA0B00BA1460A8F100E57109 /* Debug */, 447 | FA0B00BB1460A8F100E57109 /* Release */, 448 | ); 449 | defaultConfigurationIsVisible = 0; 450 | defaultConfigurationName = Release; 451 | }; 452 | FA0B00BC1460A8F100E57109 /* Build configuration list for PBXNativeTarget "GifPro" */ = { 453 | isa = XCConfigurationList; 454 | buildConfigurations = ( 455 | FA0B00BD1460A8F100E57109 /* Debug */, 456 | FA0B00BE1460A8F100E57109 /* Release */, 457 | ); 458 | defaultConfigurationIsVisible = 0; 459 | defaultConfigurationName = Release; 460 | }; 461 | /* End XCConfigurationList section */ 462 | }; 463 | rootObject = FA0B00951460A8F100E57109 /* Project object */; 464 | } 465 | -------------------------------------------------------------------------------- /GifPro/ANAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANAppDelegate.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANGifEncoder.h" 11 | #import "ANNSImageGifPixelSource.h" 12 | #import "ANCutColorTable.h" 13 | #import "ANImageListEntry.h" 14 | #import "ANExportWindow.h" 15 | 16 | @interface ANAppDelegate : NSObject { 17 | IBOutlet NSTextField * frameRateField; 18 | IBOutlet NSImageView * currentFrame; 19 | IBOutlet NSTableView * imageTable; 20 | IBOutlet NSStepper * frameRateStepper; 21 | 22 | NSIndexSet * sourceIndices; 23 | NSMutableArray * imageList; 24 | } 25 | 26 | @property (assign) IBOutlet NSWindow * window; 27 | 28 | - (IBAction)frameRateTicked:(NSStepper *)sender; 29 | - (IBAction)frameRateFieldChanged:(id)sender; 30 | - (IBAction)exportClicked:(id)sender; 31 | - (IBAction)removeSelected:(id)sender; 32 | 33 | - (void)beginExportToFile:(NSString *)path; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /GifPro/ANAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANAppDelegate.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "ANAppDelegate.h" 10 | 11 | @implementation ANAppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 16 | imageList = [[NSMutableArray alloc] init]; 17 | [imageTable becomeFirstResponder]; 18 | [imageTable registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]]; 19 | } 20 | 21 | - (IBAction)frameRateTicked:(NSStepper *)sender { 22 | [frameRateField setIntValue:[sender intValue]]; 23 | } 24 | 25 | - (IBAction)frameRateFieldChanged:(id)sender { 26 | [frameRateStepper setIntValue:[frameRateField intValue]]; 27 | [frameRateField setIntValue:[frameRateStepper intValue]]; 28 | } 29 | 30 | - (IBAction)exportClicked:(id)sender { 31 | if ([imageList count] == 0) { 32 | NSRunAlertPanel(@"No Images", @"You must add at least one external image to the animation before exporting.", @"OK", nil, nil); 33 | return; 34 | } 35 | NSSavePanel * savePanel = [NSSavePanel savePanel]; 36 | [savePanel setAllowedFileTypes:[NSArray arrayWithObject:@"gif"]]; 37 | [savePanel setMessage:@"Export a gif file"]; 38 | [savePanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { 39 | NSString * outputFile = nil; 40 | if (result == NSOKButton) { 41 | outputFile = [[savePanel URL] path]; 42 | } else return; 43 | 44 | [self performSelector:@selector(beginExportToFile:) withObject:outputFile afterDelay:0.5]; 45 | }]; 46 | } 47 | 48 | - (IBAction)removeSelected:(id)sender { 49 | NSInteger selected = [imageTable selectedRow]; 50 | if (selected >= 0) { 51 | [imageList removeObjectAtIndex:selected]; 52 | [imageTable reloadData]; 53 | } 54 | } 55 | 56 | - (void)beginExportToFile:(NSString *)path { 57 | NSMutableArray * imgFiles = [NSMutableArray array]; 58 | [imageList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) { 59 | [imgFiles addObject:[obj fileName]]; 60 | }]; 61 | NSTimeInterval delayTime = 1.0 / [frameRateField doubleValue]; 62 | ANExportWindow * export = [[ANExportWindow alloc] initWithImageFiles:imgFiles 63 | outputFile:path 64 | delay:delayTime]; 65 | [NSApp beginSheet:export modalForWindow:self.window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 66 | #if !__has_feature(objc_arc) 67 | [export release]; 68 | #endif 69 | } 70 | 71 | #pragma mark - Table View - 72 | 73 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { 74 | return [imageList count]; 75 | } 76 | 77 | - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { 78 | return [[[imageList objectAtIndex:row] fileName] lastPathComponent]; 79 | } 80 | 81 | - (void)tableViewSelectionDidChange:(NSNotification *)notification { 82 | if ([imageTable selectedRow] < 0) { 83 | [currentFrame setImage:nil]; 84 | return; 85 | } 86 | NSString * filename = [[imageList objectAtIndex:[imageTable selectedRow]] fileName]; 87 | #if __has_feature(objc_arc) 88 | [currentFrame setImage:[[NSImage alloc] initWithContentsOfFile:filename]]; 89 | #else 90 | [currentFrame setImage:[[[NSImage alloc] initWithContentsOfFile:filename] autorelease]]; 91 | #endif 92 | } 93 | 94 | #pragma mark Drag and Drop 95 | 96 | - (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard { 97 | sourceIndices = rowIndexes; 98 | NSMutableArray * fileList = [NSMutableArray array]; 99 | [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * stop) { 100 | [fileList addObject:[[imageList objectAtIndex:idx] fileName]]; 101 | }]; 102 | [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] 103 | owner:nil]; 104 | [pboard setPropertyList:fileList forType:NSFilenamesPboardType]; 105 | return YES; 106 | } 107 | 108 | - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id )info 109 | proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op { 110 | // Add code here to validate the drop 111 | if (![tableView isEnabled]) return NSDragOperationNone; 112 | return NSDragOperationCopy; 113 | } 114 | 115 | - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info 116 | row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation { 117 | NSArray * removeObjects = nil; 118 | if ([info draggingSource] == tableView) { 119 | removeObjects = [imageList objectsAtIndexes:sourceIndices]; 120 | } 121 | 122 | id selectedItem = nil; 123 | if ([tableView selectedRow] >= 0) { 124 | selectedItem = [imageList objectAtIndex:[tableView selectedRow]]; 125 | } 126 | 127 | if (![tableView isEnabled]) return NO; 128 | NSPasteboard * pboard = [info draggingPasteboard]; 129 | NSArray * fileNames = [pboard propertyListForType:NSFilenamesPboardType]; 130 | for (int i = 0; i < [fileNames count]; i++) { 131 | NSString * fileName = [fileNames objectAtIndex:i]; 132 | [imageList insertObject:[ANImageListEntry entryWithFileName:fileName] 133 | atIndex:row]; 134 | row++; 135 | } 136 | 137 | if (removeObjects) { 138 | [imageList removeObjectsInArray:removeObjects]; 139 | } 140 | if (selectedItem) { 141 | if ([imageList containsObject:selectedItem]) { 142 | NSUInteger index = [imageList indexOfObject:selectedItem]; 143 | [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; 144 | } 145 | } 146 | 147 | // Move the specified row to its new location... 148 | [tableView reloadData]; 149 | [self tableViewSelectionDidChange:nil]; 150 | return YES; 151 | } 152 | 153 | #pragma mark Memory Management 154 | 155 | #if !__has_feature(objc_arc) 156 | 157 | - (void)dealloc { 158 | [sourceIndices release]; 159 | [imageList release]; 160 | } 161 | 162 | #endif 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /GifPro/ANExportWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANExportWindow.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ANGifEncoder.h" 11 | #import "ANCutColorTable.h" 12 | #import "ANNSImageGifPixelSource.h" 13 | #import "ANGifNetscapeAppExtension.h" 14 | #import "NSImage+Resize.h" 15 | 16 | #define kExportSampleCount 2056 17 | 18 | @interface ANExportWindow : NSWindow { 19 | NSProgressIndicator * loadingBar; 20 | NSButton * cancelButton; 21 | NSTextField * activityLabel; 22 | NSThread * backgroundThread; 23 | 24 | NSArray * imageFiles; 25 | NSString * outputFile; 26 | NSTimeInterval imageDelay; 27 | } 28 | 29 | - (id)initWithImageFiles:(NSArray *)theFiles outputFile:(NSString *)aFile delay:(NSTimeInterval)dTime; 30 | - (void)cancelExport:(id)sender; 31 | 32 | - (void)exportInBackground; 33 | - (ANGifImageFrame *)imageFrameFromImage:(NSImage *)image; 34 | - (ANGifImageFrame *)imageFrameFromImage:(NSImage *)image scaled:(CGSize)scaleSize; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /GifPro/ANExportWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANExportWindow.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANExportWindow.h" 11 | 12 | @implementation ANExportWindow 13 | 14 | - (id)initWithImageFiles:(NSArray *)theFiles outputFile:(NSString *)aFile delay:(NSTimeInterval)dTime { 15 | if ((self = [super initWithContentRect:NSMakeRect(0, 0, 500, 120) styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO])) { 16 | #if __has_feature(objc_arc) 17 | outputFile = aFile; 18 | imageFiles = theFiles; 19 | #else 20 | outputFile = [aFile retain]; 21 | imageFiles = [theFiles retain]; 22 | #endif 23 | imageDelay = dTime; 24 | loadingBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(10, 50, 480, 24)]; 25 | activityLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 70, 480, 24)]; 26 | cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(405, 15, 90, 32)]; 27 | [loadingBar startAnimation:self]; 28 | [cancelButton setBezelStyle:NSRoundedBezelStyle]; 29 | [cancelButton setBordered:YES]; 30 | [cancelButton setTarget:self]; 31 | [cancelButton setAction:@selector(cancelExport:)]; 32 | [cancelButton setTitle:@"Cancel"]; 33 | [activityLabel setBordered:NO]; 34 | [activityLabel setBackgroundColor:[NSColor clearColor]]; 35 | [activityLabel setStringValue:@"Exporting..."]; 36 | [activityLabel setSelectable:NO]; 37 | [[self contentView] addSubview:loadingBar]; 38 | [[self contentView] addSubview:cancelButton]; 39 | [[self contentView] addSubview:activityLabel]; 40 | 41 | backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(exportInBackground) object:nil]; 42 | [backgroundThread start]; 43 | } 44 | return self; 45 | } 46 | 47 | - (void)cancelExport:(id)sender { 48 | [backgroundThread cancel]; 49 | #if !__has_feature(objc_arc) 50 | [backgroundThread release]; 51 | #endif 52 | backgroundThread = nil; 53 | [NSApp endSheet:self]; 54 | [self orderOut:self]; 55 | } 56 | 57 | #pragma mark Background Thread 58 | 59 | - (void)exportInBackground { 60 | @autoreleasepool { 61 | NSDate * endMin = [NSDate dateWithTimeIntervalSinceNow:1]; 62 | NSImage * firstImage = [[NSImage alloc] initWithContentsOfFile:[imageFiles objectAtIndex:0]]; 63 | ANGifImageFrame * firstFrame = [self imageFrameFromImage:firstImage]; 64 | CGSize frameSize = CGSizeMake([[firstFrame pixelSource] pixelsWide], [[firstFrame pixelSource] pixelsHigh]); 65 | ANGifEncoder * encoder = [[ANGifEncoder alloc] initWithOutputFile:outputFile 66 | size:frameSize globalColorTable:nil]; 67 | #if __has_feature(objc_arc) 68 | [encoder addApplicationExtension:[[ANGifNetscapeAppExtension alloc] initWithRepeatCount:0xffff]]; // loop 69 | #else 70 | [encoder addApplicationExtension:[[[ANGifNetscapeAppExtension alloc] initWithRepeatCount:0xffff] autorelease]]; // loop 71 | #endif 72 | 73 | [encoder addImageFrame:firstFrame]; 74 | 75 | #if __has_feature(objc_arc) != 1 76 | [firstImage release]; 77 | #endif 78 | 79 | for (int i = 1; i < [imageFiles count]; i++) { 80 | NSImage * anImage = [[NSImage alloc] initWithContentsOfFile:[imageFiles objectAtIndex:i]]; 81 | if ([[NSThread currentThread] isCancelled]) { 82 | [encoder closeFile]; 83 | #if __has_feature(objc_arc) != 1 84 | [anImage release]; 85 | [encoder release]; 86 | #endif 87 | [[NSFileManager defaultManager] removeItemAtPath:outputFile error:nil]; 88 | return; 89 | } 90 | [encoder addImageFrame:[self imageFrameFromImage:anImage scaled:frameSize]]; 91 | #if __has_feature(objc_arc) != 1 92 | [anImage release]; 93 | #endif 94 | } 95 | [encoder closeFile]; 96 | #if __has_feature(objc_arc) != 1 97 | [encoder release]; 98 | #endif 99 | if ([[NSThread currentThread] isCancelled]) { 100 | [[NSFileManager defaultManager] removeItemAtPath:outputFile error:nil]; 101 | return; 102 | } 103 | [NSThread sleepUntilDate:endMin]; 104 | [self performSelectorInBackground:@selector(cancelExport:) withObject:nil]; 105 | } 106 | } 107 | 108 | - (ANGifImageFrame *)imageFrameFromImage:(NSImage *)image { 109 | #if __has_feature(objc_arc) 110 | ANNSImageGifPixelSource * pixSource = [[ANNSImageGifPixelSource alloc] initWithImage:image]; 111 | ANColorTable * colorTable = [[ANCutColorTable alloc] initWithTransparentFirst:YES 112 | pixelSource:pixSource 113 | samples:kExportSampleCount]; 114 | return [[ANGifImageFrame alloc] initWithPixelSource:pixSource 115 | colorTable:colorTable 116 | delayTime:imageDelay]; 117 | #else 118 | ANNSImageGifPixelSource * pixSource = [[[ANNSImageGifPixelSource alloc] initWithImage:image] autorelease]; 119 | ANColorTable * colorTable = [[[ANCutColorTable alloc] initWithTransparentFirst:YES 120 | pixelSource:pixSource 121 | samples:kExportSampleCount] autorelease]; 122 | return [[[ANGifImageFrame alloc] initWithPixelSource:pixSource 123 | colorTable:colorTable 124 | delayTime:imageDelay] autorelease]; 125 | #endif 126 | } 127 | 128 | - (ANGifImageFrame *)imageFrameFromImage:(NSImage *)image scaled:(CGSize)scaleSize { 129 | if (CGSizeEqualToSize(NSSizeToCGSize([image size]), scaleSize)) { 130 | return [self imageFrameFromImage:image]; 131 | } 132 | 133 | NSImageRep * imageRep = [[image representations] objectAtIndex:0]; 134 | 135 | CGSize imageSize = CGSizeMake([imageRep pixelsWide], [imageRep pixelsHigh]); 136 | NSImage * scaledImage = image; 137 | NSUInteger offsetX = 0, offsetY = 0; 138 | 139 | if (imageSize.width > scaleSize.width || imageSize.height > scaleSize.height) { 140 | // scale the image and image size 141 | CGFloat factorX = imageSize.width / scaleSize.width; 142 | CGFloat factorY = imageSize.height / scaleSize.height; 143 | if (factorY > factorX) { 144 | imageSize.width /= factorY; 145 | imageSize.height /= factorY; 146 | } else { 147 | imageSize.width /= factorX; 148 | imageSize.height /= factorX; 149 | } 150 | scaledImage = [image imageByResizing:NSSizeFromCGSize(imageSize)]; 151 | } 152 | 153 | offsetX = (NSUInteger)round(scaleSize.width / 2.0 - imageSize.width / 2.0); 154 | offsetY = (NSUInteger)round(scaleSize.height / 2.0 - imageSize.height / 2.0); 155 | 156 | ANGifImageFrame * frame = [self imageFrameFromImage:scaledImage]; 157 | frame.offsetX = offsetX; 158 | frame.offsetY = offsetY; 159 | return frame; 160 | } 161 | 162 | #if !__has_feature(objc_arc) 163 | 164 | - (void)dealloc { 165 | [loadingBar release]; 166 | [cancelButton release]; 167 | [activityLabel release]; 168 | [backgroundThread release]; 169 | 170 | [imageFiles release]; 171 | [outputFile release]; 172 | 173 | [super dealloc]; 174 | } 175 | 176 | #endif 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /GifPro/ANImageListEntry.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANImageListEntry.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ANImageListEntry : NSObject { 12 | NSString * fileName; 13 | NSUInteger uniqueID; 14 | } 15 | 16 | @property (nonatomic, retain) NSString * fileName; 17 | @property (readwrite) NSUInteger uniqueID; 18 | 19 | + (ANImageListEntry *)entryWithFileName:(NSString *)aFileName; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /GifPro/ANImageListEntry.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANImageListEntry.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/3/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "ANImageListEntry.h" 11 | 12 | @implementation ANImageListEntry 13 | 14 | @synthesize fileName; 15 | @synthesize uniqueID; 16 | 17 | + (ANImageListEntry *)entryWithFileName:(NSString *)aFileName { 18 | ANImageListEntry * entry = [[ANImageListEntry alloc] init]; 19 | entry.fileName = aFileName; 20 | entry.uniqueID = arc4random(); 21 | #if __has_feature(objc_arc) 22 | return entry; 23 | #else 24 | return [entry autorelease]; 25 | #endif 26 | } 27 | 28 | #if !__has_feature(objc_arc) 29 | 30 | - (void)dealloc { 31 | self.fileName = nil; 32 | [super dealloc]; 33 | } 34 | 35 | #endif 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /GifPro/GifPro-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.jitsik.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2011 __MyCompanyName__. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /GifPro/GifPro-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GifPro' target in the 'GifPro' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /GifPro/NSImage+Resize.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+Resize.h 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/4/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSImage (Resize) 12 | 13 | - (NSImage *)imageByResizing:(NSSize)newSize; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /GifPro/NSImage+Resize.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+Resize.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/4/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | // Converted to Non-ARC 11/4/11 9 | 10 | #import "NSImage+Resize.h" 11 | 12 | @implementation NSImage (Resize) 13 | 14 | - (NSImage *)imageByResizing:(NSSize)newSize { 15 | NSImage * resized = [[NSImage alloc] initWithSize:newSize]; 16 | [resized lockFocus]; 17 | [self drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height) 18 | fromRect:NSZeroRect 19 | operation:NSCompositeSourceOver fraction:1]; 20 | [resized unlockFocus]; 21 | #if __has_feature(objc_arc) 22 | return resized; 23 | #else 24 | return [resized autorelease]; 25 | #endif 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /GifPro/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /GifPro/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /GifPro/en.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1070 5 | 11C74 6 | 1938 7 | 1138.23 8 | 567.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 1938 12 | 13 | 14 | NSStepper 15 | NSScroller 16 | NSTableHeaderView 17 | NSMenuItem 18 | NSMenu 19 | NSScrollView 20 | NSTextFieldCell 21 | NSImageView 22 | NSButton 23 | NSImageCell 24 | NSTableView 25 | NSButtonCell 26 | NSCustomObject 27 | NSStepperCell 28 | NSView 29 | NSWindowTemplate 30 | NSTableColumn 31 | NSTextField 32 | 33 | 34 | com.apple.InterfaceBuilder.CocoaPlugin 35 | 36 | 37 | PluginDependencyRecalculationVersion 38 | 39 | 40 | 41 | 42 | NSApplication 43 | 44 | 45 | FirstResponder 46 | 47 | 48 | NSApplication 49 | 50 | 51 | AMainMenu 52 | 53 | 54 | 55 | GifPro 56 | 57 | 1048576 58 | 2147483647 59 | 60 | NSImage 61 | NSMenuCheckmark 62 | 63 | 64 | NSImage 65 | NSMenuMixedState 66 | 67 | submenuAction: 68 | 69 | GifPro 70 | 71 | 72 | 73 | About GifPro 74 | 75 | 2147483647 76 | 77 | 78 | 79 | 80 | 81 | YES 82 | YES 83 | 84 | 85 | 1048576 86 | 2147483647 87 | 88 | 89 | 90 | 91 | 92 | Preferences… 93 | , 94 | 1048576 95 | 2147483647 96 | 97 | 98 | 99 | 100 | 101 | YES 102 | YES 103 | 104 | 105 | 1048576 106 | 2147483647 107 | 108 | 109 | 110 | 111 | 112 | Services 113 | 114 | 1048576 115 | 2147483647 116 | 117 | 118 | submenuAction: 119 | 120 | Services 121 | 122 | _NSServicesMenu 123 | 124 | 125 | 126 | 127 | YES 128 | YES 129 | 130 | 131 | 1048576 132 | 2147483647 133 | 134 | 135 | 136 | 137 | 138 | Hide GifPro 139 | h 140 | 1048576 141 | 2147483647 142 | 143 | 144 | 145 | 146 | 147 | Hide Others 148 | h 149 | 1572864 150 | 2147483647 151 | 152 | 153 | 154 | 155 | 156 | Show All 157 | 158 | 1048576 159 | 2147483647 160 | 161 | 162 | 163 | 164 | 165 | YES 166 | YES 167 | 168 | 169 | 1048576 170 | 2147483647 171 | 172 | 173 | 174 | 175 | 176 | Quit GifPro 177 | q 178 | 1048576 179 | 2147483647 180 | 181 | 182 | 183 | 184 | _NSAppleMenu 185 | 186 | 187 | 188 | 189 | File 190 | 191 | 1048576 192 | 2147483647 193 | 194 | 195 | submenuAction: 196 | 197 | File 198 | 199 | 200 | 201 | Export 202 | e 203 | 1048576 204 | 2147483647 205 | 206 | 207 | 208 | 209 | 210 | Remove Selected 211 | CA 212 | 2147483647 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | Edit 222 | 223 | 1048576 224 | 2147483647 225 | 226 | 227 | submenuAction: 228 | 229 | Edit 230 | 231 | 232 | 233 | Undo 234 | z 235 | 1048576 236 | 2147483647 237 | 238 | 239 | 240 | 241 | 242 | Redo 243 | Z 244 | 1179648 245 | 2147483647 246 | 247 | 248 | 249 | 250 | 251 | YES 252 | YES 253 | 254 | 255 | 1048576 256 | 2147483647 257 | 258 | 259 | 260 | 261 | 262 | Cut 263 | x 264 | 1048576 265 | 2147483647 266 | 267 | 268 | 269 | 270 | 271 | Copy 272 | c 273 | 1048576 274 | 2147483647 275 | 276 | 277 | 278 | 279 | 280 | Paste 281 | v 282 | 1048576 283 | 2147483647 284 | 285 | 286 | 287 | 288 | 289 | Paste and Match Style 290 | V 291 | 1572864 292 | 2147483647 293 | 294 | 295 | 296 | 297 | 298 | Delete 299 | 300 | 1048576 301 | 2147483647 302 | 303 | 304 | 305 | 306 | 307 | Select All 308 | a 309 | 1048576 310 | 2147483647 311 | 312 | 313 | 314 | 315 | 316 | YES 317 | YES 318 | 319 | 320 | 1048576 321 | 2147483647 322 | 323 | 324 | 325 | 326 | 327 | Find 328 | 329 | 1048576 330 | 2147483647 331 | 332 | 333 | submenuAction: 334 | 335 | Find 336 | 337 | 338 | 339 | Find… 340 | f 341 | 1048576 342 | 2147483647 343 | 344 | 345 | 1 346 | 347 | 348 | 349 | Find and Replace… 350 | f 351 | 1572864 352 | 2147483647 353 | 354 | 355 | 12 356 | 357 | 358 | 359 | Find Next 360 | g 361 | 1048576 362 | 2147483647 363 | 364 | 365 | 2 366 | 367 | 368 | 369 | Find Previous 370 | G 371 | 1179648 372 | 2147483647 373 | 374 | 375 | 3 376 | 377 | 378 | 379 | Use Selection for Find 380 | e 381 | 1048576 382 | 2147483647 383 | 384 | 385 | 7 386 | 387 | 388 | 389 | Jump to Selection 390 | j 391 | 1048576 392 | 2147483647 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | Spelling and Grammar 402 | 403 | 1048576 404 | 2147483647 405 | 406 | 407 | submenuAction: 408 | 409 | Spelling and Grammar 410 | 411 | 412 | 413 | Show Spelling and Grammar 414 | : 415 | 1048576 416 | 2147483647 417 | 418 | 419 | 420 | 421 | 422 | Check Document Now 423 | ; 424 | 1048576 425 | 2147483647 426 | 427 | 428 | 429 | 430 | 431 | YES 432 | YES 433 | 434 | 435 | 2147483647 436 | 437 | 438 | 439 | 440 | 441 | Check Spelling While Typing 442 | 443 | 1048576 444 | 2147483647 445 | 446 | 447 | 448 | 449 | 450 | Check Grammar With Spelling 451 | 452 | 1048576 453 | 2147483647 454 | 455 | 456 | 457 | 458 | 459 | Correct Spelling Automatically 460 | 461 | 2147483647 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | Substitutions 471 | 472 | 1048576 473 | 2147483647 474 | 475 | 476 | submenuAction: 477 | 478 | Substitutions 479 | 480 | 481 | 482 | Show Substitutions 483 | 484 | 2147483647 485 | 486 | 487 | 488 | 489 | 490 | YES 491 | YES 492 | 493 | 494 | 2147483647 495 | 496 | 497 | 498 | 499 | 500 | Smart Copy/Paste 501 | f 502 | 1048576 503 | 2147483647 504 | 505 | 506 | 1 507 | 508 | 509 | 510 | Smart Quotes 511 | g 512 | 1048576 513 | 2147483647 514 | 515 | 516 | 2 517 | 518 | 519 | 520 | Smart Dashes 521 | 522 | 2147483647 523 | 524 | 525 | 526 | 527 | 528 | Smart Links 529 | G 530 | 1179648 531 | 2147483647 532 | 533 | 534 | 3 535 | 536 | 537 | 538 | Text Replacement 539 | 540 | 2147483647 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | Transformations 550 | 551 | 2147483647 552 | 553 | 554 | submenuAction: 555 | 556 | Transformations 557 | 558 | 559 | 560 | Make Upper Case 561 | 562 | 2147483647 563 | 564 | 565 | 566 | 567 | 568 | Make Lower Case 569 | 570 | 2147483647 571 | 572 | 573 | 574 | 575 | 576 | Capitalize 577 | 578 | 2147483647 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | Speech 588 | 589 | 1048576 590 | 2147483647 591 | 592 | 593 | submenuAction: 594 | 595 | Speech 596 | 597 | 598 | 599 | Start Speaking 600 | 601 | 1048576 602 | 2147483647 603 | 604 | 605 | 606 | 607 | 608 | Stop Speaking 609 | 610 | 1048576 611 | 2147483647 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | View 624 | 625 | 1048576 626 | 2147483647 627 | 628 | 629 | submenuAction: 630 | 631 | View 632 | 633 | 634 | 635 | Show Toolbar 636 | t 637 | 1572864 638 | 2147483647 639 | 640 | 641 | 642 | 643 | 644 | Customize Toolbar… 645 | 646 | 1048576 647 | 2147483647 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | Window 657 | 658 | 1048576 659 | 2147483647 660 | 661 | 662 | submenuAction: 663 | 664 | Window 665 | 666 | 667 | 668 | Minimize 669 | m 670 | 1048576 671 | 2147483647 672 | 673 | 674 | 675 | 676 | 677 | Zoom 678 | 679 | 1048576 680 | 2147483647 681 | 682 | 683 | 684 | 685 | 686 | YES 687 | YES 688 | 689 | 690 | 1048576 691 | 2147483647 692 | 693 | 694 | 695 | 696 | 697 | Bring All to Front 698 | 699 | 1048576 700 | 2147483647 701 | 702 | 703 | 704 | 705 | _NSWindowsMenu 706 | 707 | 708 | 709 | 710 | Help 711 | 712 | 2147483647 713 | 714 | 715 | submenuAction: 716 | 717 | Help 718 | 719 | 720 | 721 | GifPro Help 722 | ? 723 | 1048576 724 | 2147483647 725 | 726 | 727 | 728 | 729 | _NSHelpMenu 730 | 731 | 732 | 733 | _NSMainMenu 734 | 735 | 736 | 15 737 | 2 738 | {{335, 390}, {568, 383}} 739 | 1954021376 740 | GifPro 741 | NSWindow 742 | 743 | 744 | {568, 383} 745 | 746 | 747 | 256 748 | 749 | 750 | 751 | 8465 752 | 753 | 754 | 755 | 2304 756 | 757 | 758 | 759 | 256 760 | {186, 367} 761 | 762 | 763 | 764 | _NS:1828 765 | YES 766 | 767 | 768 | 256 769 | {186, 17} 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | -2147483392 778 | {{224, 0}, {16, 17}} 779 | _NS:1833 780 | 781 | 782 | 783 | 183 784 | 40 785 | 1000 786 | 787 | 75628096 788 | 2048 789 | Image 790 | 791 | LucidaGrande 792 | 11 793 | 3100 794 | 795 | 796 | 3 797 | MC4zMzMzMzI5ODU2AA 798 | 799 | 800 | 6 801 | System 802 | headerTextColor 803 | 804 | 3 805 | MAA 806 | 807 | 808 | 809 | 810 | 337772096 811 | 2048 812 | Text Cell 813 | 814 | LucidaGrande 815 | 13 816 | 1044 817 | 818 | 819 | 820 | 6 821 | System 822 | controlBackgroundColor 823 | 824 | 3 825 | MC42NjY2NjY2NjY3AA 826 | 827 | 828 | 829 | 6 830 | System 831 | controlTextColor 832 | 833 | 834 | 835 | 3 836 | YES 837 | 838 | 839 | 840 | 3 841 | 2 842 | 843 | 3 844 | MQA 845 | 846 | 847 | 6 848 | System 849 | gridColor 850 | 851 | 3 852 | MC41AA 853 | 854 | 855 | 17 856 | 381681664 857 | 858 | 859 | 4 860 | 15 861 | 0 862 | YES 863 | 0 864 | 1 865 | 866 | 867 | {{1, 17}, {186, 367}} 868 | 869 | 870 | 871 | _NS:1826 872 | 873 | 874 | 4 875 | 876 | 877 | 878 | -2147483392 879 | {{224, 17}, {15, 102}} 880 | 881 | 882 | 883 | _NS:1845 884 | 885 | _doScroller: 886 | 0.99710144927536237 887 | 888 | 889 | 890 | -2147483392 891 | {{1, 119}, {223, 15}} 892 | 893 | 894 | 895 | _NS:1847 896 | 1 897 | 898 | _doScroller: 899 | 0.99465240641711228 900 | 901 | 902 | 903 | 2304 904 | 905 | 906 | 907 | {{1, 0}, {186, 17}} 908 | 909 | 910 | 911 | 912 | 913 | 4 914 | 915 | 916 | {{381, -1}, {188, 385}} 917 | 918 | 919 | 920 | _NS:1824 921 | 133682 922 | 923 | 924 | 925 | 926 | QSAAAEEgAABBmAAAQZgAAA 927 | 928 | 929 | 930 | 274 931 | 932 | Apple PDF pasteboard type 933 | Apple PICT pasteboard type 934 | Apple PNG pasteboard type 935 | NSFilenamesPboardType 936 | NeXT Encapsulated PostScript v1.2 pasteboard type 937 | NeXT TIFF v4.0 pasteboard type 938 | 939 | {{17, 47}, {359, 319}} 940 | 941 | 942 | 943 | _NS:2141 944 | YES 945 | 946 | 130560 947 | 33554432 948 | _NS:2141 949 | 0 950 | 0 951 | 2 952 | NO 953 | 954 | YES 955 | 956 | 957 | 958 | 292 959 | {{17, 21}, {76, 17}} 960 | 961 | 962 | 963 | _NS:3944 964 | YES 965 | 966 | 68288064 967 | 272630784 968 | Frame rate: 969 | 970 | _NS:3944 971 | 972 | 973 | 6 974 | System 975 | controlColor 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 292 984 | {{199, 15}, {19, 27}} 985 | 986 | 987 | 988 | _NS:3914 989 | YES 990 | 991 | 917024 992 | 0 993 | _NS:3914 994 | 995 | 1 996 | 1 997 | 100 998 | 1 999 | YES 1000 | 1001 | 1002 | 1003 | 1004 | 292 1005 | {{98, 18}, {96, 22}} 1006 | 1007 | 1008 | 1009 | _NS:903 1010 | YES 1011 | 1012 | -1804468671 1013 | 272630784 1014 | 3 1015 | 1016 | _NS:903 1017 | 1018 | YES 1019 | 1020 | 6 1021 | System 1022 | textBackgroundColor 1023 | 1024 | 1025 | 1026 | 6 1027 | System 1028 | textColor 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 289 1036 | {{267, 12}, {112, 32}} 1037 | 1038 | 1039 | 1040 | _NS:687 1041 | YES 1042 | 1043 | 67239424 1044 | 134217728 1045 | Export 1046 | 1047 | _NS:687 1048 | 1049 | -2038284033 1050 | 129 1051 | 1052 | 1053 | 200 1054 | 25 1055 | 1056 | 1057 | 1058 | {568, 383} 1059 | 1060 | 1061 | 1062 | 1063 | {{0, 0}, {1920, 1058}} 1064 | {568, 405} 1065 | {10000000000000, 10000000000000} 1066 | YES 1067 | 1068 | 1069 | ANAppDelegate 1070 | 1071 | 1072 | NSFontManager 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | terminate: 1080 | 1081 | 1082 | 1083 | 449 1084 | 1085 | 1086 | 1087 | orderFrontStandardAboutPanel: 1088 | 1089 | 1090 | 1091 | 142 1092 | 1093 | 1094 | 1095 | delegate 1096 | 1097 | 1098 | 1099 | 495 1100 | 1101 | 1102 | 1103 | performMiniaturize: 1104 | 1105 | 1106 | 1107 | 37 1108 | 1109 | 1110 | 1111 | arrangeInFront: 1112 | 1113 | 1114 | 1115 | 39 1116 | 1117 | 1118 | 1119 | toggleContinuousSpellChecking: 1120 | 1121 | 1122 | 1123 | 222 1124 | 1125 | 1126 | 1127 | undo: 1128 | 1129 | 1130 | 1131 | 223 1132 | 1133 | 1134 | 1135 | copy: 1136 | 1137 | 1138 | 1139 | 224 1140 | 1141 | 1142 | 1143 | checkSpelling: 1144 | 1145 | 1146 | 1147 | 225 1148 | 1149 | 1150 | 1151 | paste: 1152 | 1153 | 1154 | 1155 | 226 1156 | 1157 | 1158 | 1159 | stopSpeaking: 1160 | 1161 | 1162 | 1163 | 227 1164 | 1165 | 1166 | 1167 | cut: 1168 | 1169 | 1170 | 1171 | 228 1172 | 1173 | 1174 | 1175 | showGuessPanel: 1176 | 1177 | 1178 | 1179 | 230 1180 | 1181 | 1182 | 1183 | redo: 1184 | 1185 | 1186 | 1187 | 231 1188 | 1189 | 1190 | 1191 | selectAll: 1192 | 1193 | 1194 | 1195 | 232 1196 | 1197 | 1198 | 1199 | startSpeaking: 1200 | 1201 | 1202 | 1203 | 233 1204 | 1205 | 1206 | 1207 | delete: 1208 | 1209 | 1210 | 1211 | 235 1212 | 1213 | 1214 | 1215 | performZoom: 1216 | 1217 | 1218 | 1219 | 240 1220 | 1221 | 1222 | 1223 | performFindPanelAction: 1224 | 1225 | 1226 | 1227 | 241 1228 | 1229 | 1230 | 1231 | centerSelectionInVisibleArea: 1232 | 1233 | 1234 | 1235 | 245 1236 | 1237 | 1238 | 1239 | toggleGrammarChecking: 1240 | 1241 | 1242 | 1243 | 347 1244 | 1245 | 1246 | 1247 | toggleSmartInsertDelete: 1248 | 1249 | 1250 | 1251 | 355 1252 | 1253 | 1254 | 1255 | toggleAutomaticQuoteSubstitution: 1256 | 1257 | 1258 | 1259 | 356 1260 | 1261 | 1262 | 1263 | toggleAutomaticLinkDetection: 1264 | 1265 | 1266 | 1267 | 357 1268 | 1269 | 1270 | 1271 | runToolbarCustomizationPalette: 1272 | 1273 | 1274 | 1275 | 365 1276 | 1277 | 1278 | 1279 | toggleToolbarShown: 1280 | 1281 | 1282 | 1283 | 366 1284 | 1285 | 1286 | 1287 | hide: 1288 | 1289 | 1290 | 1291 | 367 1292 | 1293 | 1294 | 1295 | hideOtherApplications: 1296 | 1297 | 1298 | 1299 | 368 1300 | 1301 | 1302 | 1303 | unhideAllApplications: 1304 | 1305 | 1306 | 1307 | 370 1308 | 1309 | 1310 | 1311 | toggleAutomaticSpellingCorrection: 1312 | 1313 | 1314 | 1315 | 456 1316 | 1317 | 1318 | 1319 | orderFrontSubstitutionsPanel: 1320 | 1321 | 1322 | 1323 | 458 1324 | 1325 | 1326 | 1327 | toggleAutomaticDashSubstitution: 1328 | 1329 | 1330 | 1331 | 461 1332 | 1333 | 1334 | 1335 | toggleAutomaticTextReplacement: 1336 | 1337 | 1338 | 1339 | 463 1340 | 1341 | 1342 | 1343 | uppercaseWord: 1344 | 1345 | 1346 | 1347 | 464 1348 | 1349 | 1350 | 1351 | capitalizeWord: 1352 | 1353 | 1354 | 1355 | 467 1356 | 1357 | 1358 | 1359 | lowercaseWord: 1360 | 1361 | 1362 | 1363 | 468 1364 | 1365 | 1366 | 1367 | pasteAsPlainText: 1368 | 1369 | 1370 | 1371 | 486 1372 | 1373 | 1374 | 1375 | performFindPanelAction: 1376 | 1377 | 1378 | 1379 | 487 1380 | 1381 | 1382 | 1383 | performFindPanelAction: 1384 | 1385 | 1386 | 1387 | 488 1388 | 1389 | 1390 | 1391 | performFindPanelAction: 1392 | 1393 | 1394 | 1395 | 489 1396 | 1397 | 1398 | 1399 | showHelp: 1400 | 1401 | 1402 | 1403 | 493 1404 | 1405 | 1406 | 1407 | performFindPanelAction: 1408 | 1409 | 1410 | 1411 | 535 1412 | 1413 | 1414 | 1415 | window 1416 | 1417 | 1418 | 1419 | 532 1420 | 1421 | 1422 | 1423 | frameRateField 1424 | 1425 | 1426 | 1427 | 556 1428 | 1429 | 1430 | 1431 | frameRateTicked: 1432 | 1433 | 1434 | 1435 | 557 1436 | 1437 | 1438 | 1439 | frameRateFieldChanged: 1440 | 1441 | 1442 | 1443 | 558 1444 | 1445 | 1446 | 1447 | exportClicked: 1448 | 1449 | 1450 | 1451 | 565 1452 | 1453 | 1454 | 1455 | currentFrame 1456 | 1457 | 1458 | 1459 | 566 1460 | 1461 | 1462 | 1463 | frameRateStepper 1464 | 1465 | 1466 | 1467 | 567 1468 | 1469 | 1470 | 1471 | imageTable 1472 | 1473 | 1474 | 1475 | 568 1476 | 1477 | 1478 | 1479 | exportClicked: 1480 | 1481 | 1482 | 1483 | 576 1484 | 1485 | 1486 | 1487 | removeSelected: 1488 | 1489 | 1490 | 1491 | 578 1492 | 1493 | 1494 | 1495 | dataSource 1496 | 1497 | 1498 | 1499 | 573 1500 | 1501 | 1502 | 1503 | delegate 1504 | 1505 | 1506 | 1507 | 574 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 0 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | -2 1520 | 1521 | 1522 | File's Owner 1523 | 1524 | 1525 | -1 1526 | 1527 | 1528 | First Responder 1529 | 1530 | 1531 | -3 1532 | 1533 | 1534 | Application 1535 | 1536 | 1537 | 29 1538 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 19 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 56 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 217 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 | 83 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | 1582 | 81 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 205 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | 1612 | 1613 | 202 1614 | 1615 | 1616 | 1617 | 1618 | 198 1619 | 1620 | 1621 | 1622 | 1623 | 207 1624 | 1625 | 1626 | 1627 | 1628 | 214 1629 | 1630 | 1631 | 1632 | 1633 | 199 1634 | 1635 | 1636 | 1637 | 1638 | 203 1639 | 1640 | 1641 | 1642 | 1643 | 197 1644 | 1645 | 1646 | 1647 | 1648 | 206 1649 | 1650 | 1651 | 1652 | 1653 | 215 1654 | 1655 | 1656 | 1657 | 1658 | 218 1659 | 1660 | 1661 | 1662 | 1663 | 1664 | 1665 | 1666 | 216 1667 | 1668 | 1669 | 1670 | 1671 | 1672 | 1673 | 1674 | 200 1675 | 1676 | 1677 | 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 219 1688 | 1689 | 1690 | 1691 | 1692 | 201 1693 | 1694 | 1695 | 1696 | 1697 | 204 1698 | 1699 | 1700 | 1701 | 1702 | 220 1703 | 1704 | 1705 | 1706 | 1707 | 1708 | 1709 | 1710 | 1711 | 1712 | 1713 | 1714 | 1715 | 213 1716 | 1717 | 1718 | 1719 | 1720 | 210 1721 | 1722 | 1723 | 1724 | 1725 | 221 1726 | 1727 | 1728 | 1729 | 1730 | 208 1731 | 1732 | 1733 | 1734 | 1735 | 209 1736 | 1737 | 1738 | 1739 | 1740 | 57 1741 | 1742 | 1743 | 1744 | 1745 | 1746 | 1747 | 1748 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 58 1759 | 1760 | 1761 | 1762 | 1763 | 134 1764 | 1765 | 1766 | 1767 | 1768 | 150 1769 | 1770 | 1771 | 1772 | 1773 | 136 1774 | 1775 | 1776 | 1777 | 1778 | 144 1779 | 1780 | 1781 | 1782 | 1783 | 129 1784 | 1785 | 1786 | 1787 | 1788 | 143 1789 | 1790 | 1791 | 1792 | 1793 | 236 1794 | 1795 | 1796 | 1797 | 1798 | 131 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 149 1807 | 1808 | 1809 | 1810 | 1811 | 145 1812 | 1813 | 1814 | 1815 | 1816 | 130 1817 | 1818 | 1819 | 1820 | 1821 | 24 1822 | 1823 | 1824 | 1825 | 1826 | 1827 | 1828 | 1829 | 1830 | 1831 | 1832 | 92 1833 | 1834 | 1835 | 1836 | 1837 | 5 1838 | 1839 | 1840 | 1841 | 1842 | 239 1843 | 1844 | 1845 | 1846 | 1847 | 23 1848 | 1849 | 1850 | 1851 | 1852 | 295 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 296 1861 | 1862 | 1863 | 1864 | 1865 | 1866 | 1867 | 1868 | 1869 | 297 1870 | 1871 | 1872 | 1873 | 1874 | 298 1875 | 1876 | 1877 | 1878 | 1879 | 211 1880 | 1881 | 1882 | 1883 | 1884 | 1885 | 1886 | 1887 | 212 1888 | 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 195 1897 | 1898 | 1899 | 1900 | 1901 | 196 1902 | 1903 | 1904 | 1905 | 1906 | 346 1907 | 1908 | 1909 | 1910 | 1911 | 348 1912 | 1913 | 1914 | 1915 | 1916 | 1917 | 1918 | 1919 | 349 1920 | 1921 | 1922 | 1923 | 1924 | 1925 | 1926 | 1927 | 1928 | 1929 | 1930 | 1931 | 1932 | 1933 | 350 1934 | 1935 | 1936 | 1937 | 1938 | 351 1939 | 1940 | 1941 | 1942 | 1943 | 354 1944 | 1945 | 1946 | 1947 | 1948 | 371 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 372 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 420 1970 | 1971 | 1972 | 1973 | 1974 | 450 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 451 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 452 1993 | 1994 | 1995 | 1996 | 1997 | 453 1998 | 1999 | 2000 | 2001 | 2002 | 454 2003 | 2004 | 2005 | 2006 | 2007 | 457 2008 | 2009 | 2010 | 2011 | 2012 | 459 2013 | 2014 | 2015 | 2016 | 2017 | 460 2018 | 2019 | 2020 | 2021 | 2022 | 462 2023 | 2024 | 2025 | 2026 | 2027 | 465 2028 | 2029 | 2030 | 2031 | 2032 | 466 2033 | 2034 | 2035 | 2036 | 2037 | 485 2038 | 2039 | 2040 | 2041 | 2042 | 490 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | 2049 | 2050 | 491 2051 | 2052 | 2053 | 2054 | 2055 | 2056 | 2057 | 2058 | 492 2059 | 2060 | 2061 | 2062 | 2063 | 494 2064 | 2065 | 2066 | 2067 | 2068 | 534 2069 | 2070 | 2071 | 2072 | 2073 | 536 2074 | 2075 | 2076 | 2077 | 2078 | 2079 | 2080 | 2081 | 2082 | 2083 | 2084 | 537 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 538 2093 | 2094 | 2095 | 2096 | 2097 | 540 2098 | 2099 | 2100 | 2101 | 2102 | 541 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 544 2111 | 2112 | 2113 | 2114 | 2115 | 545 2116 | 2117 | 2118 | 2119 | 2120 | 546 2121 | 2122 | 2123 | 2124 | 2125 | 2126 | 2127 | 2128 | 547 2129 | 2130 | 2131 | 2132 | 2133 | 548 2134 | 2135 | 2136 | 2137 | 2138 | 2139 | 2140 | 2141 | 549 2142 | 2143 | 2144 | 2145 | 2146 | 552 2147 | 2148 | 2149 | 2150 | 2151 | 2152 | 2153 | 2154 | 553 2155 | 2156 | 2157 | 2158 | 2159 | 554 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | 2166 | 2167 | 555 2168 | 2169 | 2170 | 2171 | 2172 | 563 2173 | 2174 | 2175 | 2176 | 2177 | 2178 | 2179 | 2180 | 564 2181 | 2182 | 2183 | 2184 | 2185 | 575 2186 | 2187 | 2188 | 2189 | 2190 | 577 2191 | 2192 | 2193 | 2194 | 2195 | 2196 | 2197 | com.apple.InterfaceBuilder.CocoaPlugin 2198 | com.apple.InterfaceBuilder.CocoaPlugin 2199 | com.apple.InterfaceBuilder.CocoaPlugin 2200 | com.apple.InterfaceBuilder.CocoaPlugin 2201 | com.apple.InterfaceBuilder.CocoaPlugin 2202 | com.apple.InterfaceBuilder.CocoaPlugin 2203 | com.apple.InterfaceBuilder.CocoaPlugin 2204 | com.apple.InterfaceBuilder.CocoaPlugin 2205 | com.apple.InterfaceBuilder.CocoaPlugin 2206 | com.apple.InterfaceBuilder.CocoaPlugin 2207 | com.apple.InterfaceBuilder.CocoaPlugin 2208 | com.apple.InterfaceBuilder.CocoaPlugin 2209 | com.apple.InterfaceBuilder.CocoaPlugin 2210 | com.apple.InterfaceBuilder.CocoaPlugin 2211 | com.apple.InterfaceBuilder.CocoaPlugin 2212 | com.apple.InterfaceBuilder.CocoaPlugin 2213 | com.apple.InterfaceBuilder.CocoaPlugin 2214 | com.apple.InterfaceBuilder.CocoaPlugin 2215 | com.apple.InterfaceBuilder.CocoaPlugin 2216 | com.apple.InterfaceBuilder.CocoaPlugin 2217 | com.apple.InterfaceBuilder.CocoaPlugin 2218 | com.apple.InterfaceBuilder.CocoaPlugin 2219 | com.apple.InterfaceBuilder.CocoaPlugin 2220 | com.apple.InterfaceBuilder.CocoaPlugin 2221 | com.apple.InterfaceBuilder.CocoaPlugin 2222 | com.apple.InterfaceBuilder.CocoaPlugin 2223 | com.apple.InterfaceBuilder.CocoaPlugin 2224 | com.apple.InterfaceBuilder.CocoaPlugin 2225 | com.apple.InterfaceBuilder.CocoaPlugin 2226 | com.apple.InterfaceBuilder.CocoaPlugin 2227 | com.apple.InterfaceBuilder.CocoaPlugin 2228 | com.apple.InterfaceBuilder.CocoaPlugin 2229 | com.apple.InterfaceBuilder.CocoaPlugin 2230 | com.apple.InterfaceBuilder.CocoaPlugin 2231 | com.apple.InterfaceBuilder.CocoaPlugin 2232 | com.apple.InterfaceBuilder.CocoaPlugin 2233 | com.apple.InterfaceBuilder.CocoaPlugin 2234 | com.apple.InterfaceBuilder.CocoaPlugin 2235 | com.apple.InterfaceBuilder.CocoaPlugin 2236 | com.apple.InterfaceBuilder.CocoaPlugin 2237 | com.apple.InterfaceBuilder.CocoaPlugin 2238 | com.apple.InterfaceBuilder.CocoaPlugin 2239 | com.apple.InterfaceBuilder.CocoaPlugin 2240 | com.apple.InterfaceBuilder.CocoaPlugin 2241 | com.apple.InterfaceBuilder.CocoaPlugin 2242 | com.apple.InterfaceBuilder.CocoaPlugin 2243 | com.apple.InterfaceBuilder.CocoaPlugin 2244 | com.apple.InterfaceBuilder.CocoaPlugin 2245 | com.apple.InterfaceBuilder.CocoaPlugin 2246 | com.apple.InterfaceBuilder.CocoaPlugin 2247 | com.apple.InterfaceBuilder.CocoaPlugin 2248 | com.apple.InterfaceBuilder.CocoaPlugin 2249 | com.apple.InterfaceBuilder.CocoaPlugin 2250 | com.apple.InterfaceBuilder.CocoaPlugin 2251 | com.apple.InterfaceBuilder.CocoaPlugin 2252 | com.apple.InterfaceBuilder.CocoaPlugin 2253 | com.apple.InterfaceBuilder.CocoaPlugin 2254 | {{380, 496}, {480, 360}} 2255 | 2256 | com.apple.InterfaceBuilder.CocoaPlugin 2257 | com.apple.InterfaceBuilder.CocoaPlugin 2258 | com.apple.InterfaceBuilder.CocoaPlugin 2259 | com.apple.InterfaceBuilder.CocoaPlugin 2260 | com.apple.InterfaceBuilder.CocoaPlugin 2261 | com.apple.InterfaceBuilder.CocoaPlugin 2262 | com.apple.InterfaceBuilder.CocoaPlugin 2263 | com.apple.InterfaceBuilder.CocoaPlugin 2264 | com.apple.InterfaceBuilder.CocoaPlugin 2265 | com.apple.InterfaceBuilder.CocoaPlugin 2266 | com.apple.InterfaceBuilder.CocoaPlugin 2267 | com.apple.InterfaceBuilder.CocoaPlugin 2268 | com.apple.InterfaceBuilder.CocoaPlugin 2269 | com.apple.InterfaceBuilder.CocoaPlugin 2270 | com.apple.InterfaceBuilder.CocoaPlugin 2271 | com.apple.InterfaceBuilder.CocoaPlugin 2272 | com.apple.InterfaceBuilder.CocoaPlugin 2273 | com.apple.InterfaceBuilder.CocoaPlugin 2274 | com.apple.InterfaceBuilder.CocoaPlugin 2275 | com.apple.InterfaceBuilder.CocoaPlugin 2276 | com.apple.InterfaceBuilder.CocoaPlugin 2277 | com.apple.InterfaceBuilder.CocoaPlugin 2278 | com.apple.InterfaceBuilder.CocoaPlugin 2279 | com.apple.InterfaceBuilder.CocoaPlugin 2280 | com.apple.InterfaceBuilder.CocoaPlugin 2281 | com.apple.InterfaceBuilder.CocoaPlugin 2282 | com.apple.InterfaceBuilder.CocoaPlugin 2283 | com.apple.InterfaceBuilder.CocoaPlugin 2284 | com.apple.InterfaceBuilder.CocoaPlugin 2285 | com.apple.InterfaceBuilder.CocoaPlugin 2286 | com.apple.InterfaceBuilder.CocoaPlugin 2287 | com.apple.InterfaceBuilder.CocoaPlugin 2288 | com.apple.InterfaceBuilder.CocoaPlugin 2289 | com.apple.InterfaceBuilder.CocoaPlugin 2290 | com.apple.InterfaceBuilder.CocoaPlugin 2291 | com.apple.InterfaceBuilder.CocoaPlugin 2292 | com.apple.InterfaceBuilder.CocoaPlugin 2293 | com.apple.InterfaceBuilder.CocoaPlugin 2294 | com.apple.InterfaceBuilder.CocoaPlugin 2295 | com.apple.InterfaceBuilder.CocoaPlugin 2296 | com.apple.InterfaceBuilder.CocoaPlugin 2297 | com.apple.InterfaceBuilder.CocoaPlugin 2298 | com.apple.InterfaceBuilder.CocoaPlugin 2299 | com.apple.InterfaceBuilder.CocoaPlugin 2300 | com.apple.InterfaceBuilder.CocoaPlugin 2301 | 2302 | 2303 | 2304 | 2305 | 2306 | 578 2307 | 2308 | 2309 | 2310 | 2311 | ANAppDelegate 2312 | NSObject 2313 | 2314 | id 2315 | id 2316 | NSStepper 2317 | id 2318 | 2319 | 2320 | 2321 | exportClicked: 2322 | id 2323 | 2324 | 2325 | frameRateFieldChanged: 2326 | id 2327 | 2328 | 2329 | frameRateTicked: 2330 | NSStepper 2331 | 2332 | 2333 | removeSelected: 2334 | id 2335 | 2336 | 2337 | 2338 | NSImageView 2339 | NSTextField 2340 | NSStepper 2341 | NSTableView 2342 | NSWindow 2343 | 2344 | 2345 | 2346 | currentFrame 2347 | NSImageView 2348 | 2349 | 2350 | frameRateField 2351 | NSTextField 2352 | 2353 | 2354 | frameRateStepper 2355 | NSStepper 2356 | 2357 | 2358 | imageTable 2359 | NSTableView 2360 | 2361 | 2362 | window 2363 | NSWindow 2364 | 2365 | 2366 | 2367 | IBProjectSource 2368 | ./Classes/ANAppDelegate.h 2369 | 2370 | 2371 | 2372 | 2373 | 0 2374 | IBCocoaFramework 2375 | YES 2376 | 3 2377 | 2378 | {9, 8} 2379 | {7, 2} 2380 | 2381 | 2382 | 2383 | -------------------------------------------------------------------------------- /GifPro/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GifPro 4 | // 5 | // Created by Alex Nichol on 11/1/11. 6 | // Copyright (c) 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The ANGif Library 2 | ================= 3 | 4 | ANGif is a small class library that can be used to encode Graphics Interchange Format files using a simple interface. It could easily be ported to platforms other than Cocoa (e.g. UIKit/CocoaTouch). The `ANGifEncoder` class is the root of all GIF encoding, and can be used as follows: 5 | 6 | ANGifEncoder * encoder = [[ANGifEncoder alloc] initWithOutputFile:@"myFile.gif" size:CGSizeMake(100, 100) globalColorTable:nil]; 7 | [encoder addApplicationExtension:[[ANGifNetscapeAppExtension alloc] init]]; 8 | [encoder addImageFrame:anImageFrame]; 9 | [encoder addImageFrame:anotherImageFrame]; 10 | [encoder closeFile]; 11 | 12 | The `addImageFrame:` method takes an instance of `ANGifImageFrame`, a basic class for enclosing images. The class itself can be instantiated using the `initWithPixelSource:colorTable:delayTime:` method. As of November 4th, 2011, the best color table to use is `ANCutColorTable`. 13 | 14 | The `ANGifImageFramePixelSource` protocol is essential to the functionality of ANGif. It is suggested that you make a class that wraps a native image class such as `NSBitmapImageRep`, and implements all of the required methods. 15 | 16 | The GifPro Project 17 | ================== 18 | 19 | The Xcode project included with this repository is GifPro, a Mac OS X demo of what ANGif is capable of. The project includes `ANNSImageGifPixelSource`, an `NSBitmapImageRep` wrapper that conforms to the `ANGifImageFramePixelSource` protocol. The `ANExportWindow` class includes most of the code that directly interfaces the ANGif library. 20 | 21 | Contribute a Color Table 22 | ------------------------ 23 | 24 | The GIF format works in a way such that files may only have 256 colors per image. This being said, algorithms exist to accurately calculate the best possible choices of colors for the 256-entry color table. The ANGif library is easily extendable to accomedate any color table algorithm that may be designed in the future. 25 | 26 | If you are looking to implement a color table for ANGif, it is suggested that you have a look at the code for the `ANColorTable` base class. If you are still uncertain of exactly what you need to do to implement a color table, maybe have a look at `ANCutColorTable`. This was the first color table to be implemented for ANGif, and therefore should be a role model for those that follow. 27 | --------------------------------------------------------------------------------