iOS支持Gif格式图片动画

来源:互联网 发布:淘宝商家电话怎么查 编辑:程序博客网 时间:2024/06/05 02:55

//AnimatedGif.h
#import <UIKit/UIKit.h>

@interface AnimatedGifFrame : NSObject
{
NSData *data;
NSData *header;
double delay;
int disposalMethod;
CGRect area;
}

@property (nonatomic, copy) NSData *header;
@property (nonatomic, copy) NSData *data;
@property (nonatomic) double delay;
@property (nonatomic) int disposalMethod;
@property (nonatomic) CGRect area;

@end

@interface AnimatedGif : NSObject
{
NSData *GIF_pointer;
NSMutableData *GIF_buffer;
NSMutableData *GIF_screen;
NSMutableData *GIF_global;
NSMutableArray *GIF_frames;

bool busyDecoding;

int GIF_sorted;
int GIF_colorS;
int GIF_colorC;
int GIF_colorF;

int dataPointer;

}

@property bool busyDecoding;

+ (id)gifWithPath:(NSString*)absolutePath;
- (id)initWithPath:(NSString*)absolutePath;
- (void) decodeGIF:(NSData *)GIF_Data;
- (void) GIFReadExtensions;
- (void) GIFReadDescriptor;
- (bool) GIFGetBytes:(int)length;
- (bool) GIFSkipBytes: (int) length;
- (NSData*) getFrameAsDataAtIndex:(int)index;
- (NSArray *)frames;

@end

//AnimatedGif.m
#import “AnimatedGif.h”

@implementation AnimatedGifFrame

@synthesize data, delay, disposalMethod, area, header;

- (void) dealloc
{
[data release];
[header release];
[super dealloc];
}

@end

@implementation AnimatedGif

@synthesize busyDecoding;

+ (id)gifWithPath:(NSString*)absolutePath
{
AnimatedGif* gif = [[AnimatedGif alloc] initWithPath:absolutePath];

return [gif autorelease];
}

- (id) init
{
self = [super init];
if (self) {

}
return self;
}

- (id)initWithPath:(NSString*)absolutePath
{
self = [self init];
if (self) {
[self decodeGIF:[NSData dataWithContentsOfFile:absolutePath]];

}
return self;
}

- (void) dealloc
{
if (GIF_buffer != nil)
{
[GIF_buffer release];
}

if (GIF_screen != nil)
{
[GIF_screen release];
}

if (GIF_global != nil)
{
[GIF_global release];
}

[GIF_frames release];

[super dealloc];
}

//
- (void)decodeGIF:(NSData *)GIFData
{
GIF_pointer = GIFData;

if (GIF_buffer != nil)
{
[GIF_buffer release];
}

if (GIF_global != nil)
{
[GIF_global release];
}

if (GIF_screen != nil)
{
[GIF_screen release];
}

[GIF_frames release];

GIF_buffer = [[NSMutableData alloc] init];
GIF_global = [[NSMutableData alloc] init];
GIF_screen = [[NSMutableData alloc] init];
GIF_frames = [[NSMutableArray alloc] init];

// Reset file counters to 0
dataPointer = 0;

[self GIFSkipBytes: 6]; // GIF89a, throw away
[self GIFGetBytes: 7]; // Logical Screen Descriptor

// Deep copy
[GIF_screen setData: GIF_buffer];

// Copy the read bytes into a local buffer on the stack
// For easy byte access in the following lines.
int length = [GIF_buffer length];
unsigned char aBuffer[length];
[GIF_buffer getBytes:aBuffer length:length];

if (aBuffer[4] & 0×80) GIF_colorF = 1; else GIF_colorF = 0;
if (aBuffer[4] & 0×08) GIF_sorted = 1; else GIF_sorted = 0;
GIF_colorC = (aBuffer[4] & 0×07);
GIF_colorS = 2 << GIF_colorC;

if (GIF_colorF == 1)
{
[self GIFGetBytes: (3 * GIF_colorS)];

// Deep copy
[GIF_global setData:GIF_buffer];
}

unsigned char bBuffer[1];
while ([self GIFGetBytes:1] == YES)
{
[GIF_buffer getBytes:bBuffer length:1];

if (bBuffer[0] == 0x3B)
{ // This is the end
break;
}

switch (bBuffer[0])
{
case 0×21:
// Graphic Control Extension (#n of n)
[self GIFReadExtensions];
break;
case 0x2C:
// Image Descriptor (#n of n)
[self GIFReadDescriptor];
break;
}
}

// clean up stuff
[GIF_buffer release];
GIF_buffer = nil;

[GIF_screen release];
GIF_screen = nil;

[GIF_global release];
GIF_global = nil;
}

//
// Returns a subframe as NSMutableData.
// Returns nil when frame does not exist.
//
// Use this to write a subframe to the filesystems (cache etc);
- (NSData*) getFrameAsDataAtIndex:(int)index
{
if (index < [GIF_frames count])
{
return ((AnimatedGifFrame *)[GIF_frames objectAtIndex:index]).data;
}
else
{
return nil;
}
}

//
// Returns a subframe as an autorelease UIImage.
// Returns nil when frame does not exist.
//
// Use this to put a subframe on your GUI.
- (UIImage*) getFrameAsImageAtIndex:(int)index
{
NSData *frameData = [self getFrameAsDataAtIndex: index];
UIImage *image = nil;

if (frameData != nil)
{
image = [UIImage imageWithData:frameData];
}

return image;
}

//
// This method converts the arrays of GIF data to an animation, counting
// up all the seperate frame delays, and setting that to the total duration
// since the iPhone Cocoa framework does not allow you to set per frame
// delays.
//
// Returns nil when there are no frames present in the GIF, or
// an autorelease UIImageView* with the animation.

- (void)GIFReadExtensions
{
// 21! But we still could have an Application Extension,
// so we want to check for the full signature.
unsigned char cur[1], prev[1];
[self GIFGetBytes:1];
[GIF_buffer getBytes:cur length:1];

while (cur[0] != 0×00)
{

// TODO: Known bug, the sequence F9 04 could occur in the Application Extension, we
//       should check whether this combo follows directly after the 21.
if (cur[0] == 0×04 && prev[0] == 0xF9)
{
[self GIFGetBytes:5];

AnimatedGifFrame *frame = [[AnimatedGifFrame alloc] init];

unsigned char buffer[5];
[GIF_buffer getBytes:buffer length:5];
frame.disposalMethod = (buffer[0] & 0x1c) >> 2;
//NSLog(@”flags=%x, dm=%x”, (int)(buffer[0]), frame.disposalMethod);

// We save the delays for easy access.
frame.delay = (buffer[1] | buffer[2] << 8);

unsigned char board[8];
board[0] = 0×21;
board[1] = 0xF9;
board[2] = 0×04;

for(int i = 3, a = 0; a < 5; i++, a++)
{
board[i] = buffer[a];
}

frame.header = [NSData dataWithBytes:board length:8];
[GIF_frames addObject:frame];
[frame release];
break;
}

prev[0] = cur[0];
[self GIFGetBytes:1];
[GIF_buffer getBytes:cur length:1];
}
}

- (void) GIFReadDescriptor
{
[self GIFGetBytes:9];

// Deep copy
NSMutableData *GIF_screenTmp = [NSMutableData dataWithData:GIF_buffer];

unsigned char aBuffer[9];
[GIF_buffer getBytes:aBuffer length:9];

CGRect rect;
rect.origin.x = ((int)aBuffer[1] << 8 ) | aBuffer[0];
rect.origin.y = ((int)aBuffer[3] << 8 ) | aBuffer[2];
rect.size.width = ((int)aBuffer[5] << 8 ) | aBuffer[4];
rect.size.height = ((int)aBuffer[7] << 8 ) | aBuffer[6];

AnimatedGifFrame *frame = [GIF_frames lastObject];
frame.area = rect;

if (aBuffer[8] & 0×80) GIF_colorF = 1; else GIF_colorF = 0;

unsigned char GIF_code = GIF_colorC, GIF_sort = GIF_sorted;

if (GIF_colorF == 1)
{
GIF_code = (aBuffer[8] & 0×07);

if (aBuffer[8] & 0×20)
{
GIF_sort = 1;
}
else
{
GIF_sort = 0;
}
}

int GIF_size = (2 << GIF_code);

size_t blength = [GIF_screen length];
unsigned char bBuffer[blength];
[GIF_screen getBytes:bBuffer length:blength];

bBuffer[4] = (bBuffer[4] & 0×70);
bBuffer[4] = (bBuffer[4] | 0×80);
bBuffer[4] = (bBuffer[4] | GIF_code);

if (GIF_sort)
{
bBuffer[4] |= 0×08;
}

NSMutableData *GIF_string = [NSMutableData dataWithData:[[NSString stringWithString:@"GIF89a"] dataUsingEncoding: NSUTF8StringEncoding]];
[GIF_screen setData:[NSData dataWithBytes:bBuffer length:blength]];
[GIF_string appendData: GIF_screen];

if (GIF_colorF == 1)
{
[self GIFGetBytes:(3 * GIF_size)];
[GIF_string appendData:GIF_buffer];
}
else
{
[GIF_string appendData:GIF_global];
}

// Add Graphic Control Extension Frame (for transparancy)
[GIF_string appendData:frame.header];

char endC = 0x2c;
[GIF_string appendBytes:&endC length:sizeof(endC)];

size_t clength = [GIF_screenTmp length];
unsigned char cBuffer[clength];
[GIF_screenTmp getBytes:cBuffer length:clength];

cBuffer[8] &= 0×40;

[GIF_screenTmp setData:[NSData dataWithBytes:cBuffer length:clength]];

[GIF_string appendData: GIF_screenTmp];
[self GIFGetBytes:1];
[GIF_string appendData: GIF_buffer];

while (true)
{
[self GIFGetBytes:1];
[GIF_string appendData: GIF_buffer];

unsigned char dBuffer[1];
[GIF_buffer getBytes:dBuffer length:1];

long u = (long) dBuffer[0];

if (u != 0×00)
{
[self GIFGetBytes:u];
[GIF_string appendData: GIF_buffer];
}
else
{
break;
}

}

endC = 0x3b;
[GIF_string appendBytes:&endC length:sizeof(endC)];

// save the frame into the array of frames
frame.data = GIF_string;
}


- (bool) GIFGetBytes: (int) length
{
if (GIF_buffer != nil)
{
[GIF_buffer release]; // Release old buffer
GIF_buffer = nil;
}

if ([GIF_pointer length] >= dataPointer + length) // Don’t read across the edge of the file..
{
GIF_buffer = (id)[[GIF_pointer subdataWithRange:NSMakeRange(dataPointer, length)] retain];
dataPointer += length;
return YES;
}
else
{
return NO;
}
}


- (bool) GIFSkipBytes: (int) length
{
if ([GIF_pointer length] >= dataPointer + length)
{
dataPointer += length;
return YES;
}
else
{
return NO;
}

}

- (NSArray *)frames
{
NSMutableArray *frames = [NSMutableArray arrayWithCapacity:100];
for(int i=0; i<100; i++)
{
UIImage *aImage = [self getFrameAsImageAtIndex:i];
if(!aImage)
break;
else
[frames addObject:aImage];
}
return frames;
}

@end

初始化方法

LoadingAnimationView继承自UIImageView

@implementation LoadingAnimationView
@synthesize gifs = _gifs;

- (id)initWithFrame:(CGRect)frame{

self = [super initWithFrame:frame];
if (self) {

self.backgroundColor = [UIColor clearColor];
AnimatedGif *aniGif = [[AnimatedGif alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:@”loading” ofType:@”gif”];
[aniGif decodeGIF:[NSData dataWithContentsOfFile:path]];

_gifs = [[aniGif frames] retain];
self.animationImages = _gifs;
self.animationDuration = 0.1f*[_gifs count];
self.animationRepeatCount = 9999;
[aniGif release];
}
return self;
}

-(void)startAnimating
{
if(self.hidden)
self.hidden = NO;
[super startAnimating];
}

-(void)stopAnimating
{
[super stopAnimating];
self.hidden = YES;
}

- (void)dealloc {
[_gifs release];
[super dealloc];
}

0 0
原创粉丝点击