ios 展示gif动画


#import "SCGIFImageView.h"
NSString* filePath = [[NSBundle mainBundle] pathForResource:@"1.gif" ofType:nil];
SCGIFImageView* gifImageView = [[[SCGIFImageView alloc] initWithGIFFile:filePath] autorelease];
gifImageView.frame = CGRectMake(0, 0, gifImageView.image.size.width, gifImageView.image.size.height);
gifImageView.center = self.view.center;
[self.view addSubview:gifImageView];

SCGIFImageView.h

//
// SCGIFImageView.h
// TestGIF
//
// Created by shichangone on 11-7-12.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import

@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 SCGIFImageView : UIImageView {
NSData *GIF_pointer;
NSMutableData *GIF_buffer;
NSMutableData *GIF_screen;
NSMutableData *GIF_global;
NSMutableArray *GIF_frames;

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

int dataPointer;
}
@property (nonatomic, retain) NSMutableArray *GIF_frames;

- (id)initWithGIFFile:(NSString*)gifFilePath;
- (id)initWithGIFData:(NSData*)gifImageData;

- (void)loadImageData;

+ (NSMutableArray*)getGifFrames:(NSData*)gifImageData;
+ (BOOL)isGifImage:(NSData*)imageData;

- (void) decodeGIF:(NSData *)GIFData;
- (void) GIFReadExtensions;
- (void) GIFReadDescriptor;
- (bool) GIFGetBytes:(int)length;
- (bool) GIFSkipBytes: (int) length;
- (NSData*) getFrameAsDataAtIndex:(int)index;
- (UIImage*) getFrameAsImageAtIndex:(int)index;

@end


SCGIFImageView.m

//
// SCGIFImageView.m
// TestGIF
//
// Created by shichangone on 11-7-12.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "SCGIFImageView.h"

@implementation AnimatedGifFrame

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

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

@end

@implementation SCGIFImageView
@synthesize GIF_frames;

+ (BOOL)isGifImage:(NSData*)imageData {
const char* buf = (const char*)[imageData bytes];
if (buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x38) {
return YES;
}
return NO;
}

+ (NSMutableArray*)getGifFrames:(NSData*)gifImageData {
SCGIFImageView* gifImageView = [[SCGIFImageView alloc] initWithGIFData:gifImageData];
if (!gifImageView) {
return nil;
}

NSMutableArray* gifFrames = gifImageView.GIF_frames;
[[gifFrames retain] autorelease];
[gifImageView release];
return gifFrames;
}

- (id)initWithGIFFile:(NSString*)gifFilePath {
NSData* imageData = [NSData dataWithContentsOfFile:gifFilePath];
return [self initWithGIFData:imageData];
}

- (id)initWithGIFData:(NSData*)gifImageData {
if (gifImageData.length < 4) {
return nil;
}

if (![SCGIFImageView isGifImage:gifImageData]) {
UIImage* image = [UIImage imageWithData:gifImageData];
return [super initWithImage:image];
}

[self decodeGIF:gifImageData];

if (GIF_frames.count <= 0) {
UIImage* image = [UIImage imageWithData:gifImageData];
return [super initWithImage:image];
}

self = [super init];
if (self) {
[self loadImageData];
}

return self;
}

- (void)setGIF_frames:(NSMutableArray *)gifFrames {
[gifFrames retain];

if (GIF_frames) {
[GIF_frames release];
}
GIF_frames = gifFrames;

[self loadImageData];
}

- (void)loadImageData {
// Add all subframes to the animation
NSMutableArray *array = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < [GIF_frames count]; i++)
{
[array addObject: [self getFrameAsImageAtIndex:i]];
}

NSMutableArray *overlayArray = [[NSMutableArray alloc] init];
UIImage *firstImage = [array objectAtIndex:0];
CGSize size = firstImage.size;
CGRect rect = CGRectZero;
rect.size = size;

UIGraphicsBeginImageContext(size);
CGContextRef ctx = UIGraphicsGetCurrentContext();

int i = 0;
AnimatedGifFrame *lastFrame = nil;
for (UIImage *image in array)
{
// Get Frame
AnimatedGifFrame *frame = [GIF_frames objectAtIndex:i];

// Initialize Flag
UIImage *previousCanvas = nil;

// Save Context
CGContextSaveGState(ctx);
// Change CTM
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0.0, -size.height);

// Check if lastFrame exists
CGRect clipRect;

// Disposal Method (Operations before draw frame)
switch (frame.disposalMethod)
{
case 1: // Do not dispose (draw over context)
// Create Rect (y inverted) to clipping
clipRect = CGRectMake(frame.area.origin.x, size.height - frame.area.size.height - frame.area.origin.y, frame.area.size.width, frame.area.size.height);
// Clip Context
CGContextClipToRect(ctx, clipRect);
break;
case 2: // Restore to background the rect when the actual frame will go to be drawed
// Create Rect (y inverted) to clipping
clipRect = CGRectMake(frame.area.origin.x, size.height - frame.area.size.height - frame.area.origin.y, frame.area.size.width, frame.area.size.height);
// Clip Context
CGContextClipToRect(ctx, clipRect);
break;
case 3: // Restore to Previous
// Get Canvas
previousCanvas = UIGraphicsGetImageFromCurrentImageContext();

// Create Rect (y inverted) to clipping
clipRect = CGRectMake(frame.area.origin.x, size.height - frame.area.size.height - frame.area.origin.y, frame.area.size.width, frame.area.size.height);
// Clip Context
CGContextClipToRect(ctx, clipRect);
break;
}

// Draw Actual Frame
CGContextDrawImage(ctx, rect, image.CGImage);
// Restore State
CGContextRestoreGState(ctx);

//delay must larger than 0, the minimum delay in firefox is 10.
if (frame.delay <= 0) {
frame.delay = 10;
}
[overlayArray addObject:UIGraphicsGetImageFromCurrentImageContext()];

// Set Last Frame
lastFrame = frame;

// Disposal Method (Operations afte draw frame)
switch (frame.disposalMethod)
{
case 2: // Restore to background color the zone of the actual frame
// Save Context
CGContextSaveGState(ctx);
// Change CTM
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0.0, -size.height);
// Clear Context
CGContextClearRect(ctx, clipRect);
// Restore Context
CGContextRestoreGState(ctx);
break;
case 3: // Restore to Previous Canvas
// Save Context
CGContextSaveGState(ctx);
// Change CTM
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0.0, -size.height);
// Clear Context
CGContextClearRect(ctx, lastFrame.area);
// Draw previous frame
CGContextDrawImage(ctx, rect, previousCanvas.CGImage);
// Restore State
CGContextRestoreGState(ctx);
break;
}

// Increment counter
i++;
}
UIGraphicsEndImageContext();

[self setImage:[overlayArray objectAtIndex:0]];
[self setAnimationImages:overlayArray];

[overlayArray release];
[array release];

// Count up the total delay, since Cocoa doesn't do per frame delays.
double total = 0;
for (AnimatedGifFrame *frame in GIF_frames) {
total += frame.delay;
}

// GIFs store the delays as 1/100th of a second,
// UIImageViews want it in seconds.
[self setAnimationDuration:total/100];

// Repeat infinite
[self setAnimationRepeatCount:0];

[self startAnimating];
}

- (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] & 0x80) GIF_colorF = 1; else GIF_colorF = 0;
if (aBuffer[4] & 0x08) GIF_sorted = 1; else GIF_sorted = 0;
GIF_colorC = (aBuffer[4] & 0x07);
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 0x21:
// 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;
}

- (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] != 0x00)
{

// 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] == 0x04 && 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] = 0x21;
board[1] = 0xF9;
board[2] = 0x04;

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] & 0x80) 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] & 0x07);

if (aBuffer[8] & 0x20)
{
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] & 0x70);
bBuffer[4] = (bBuffer[4] | 0x80);
bBuffer[4] = (bBuffer[4] | GIF_code);

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

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] &= 0x40;

[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 != 0x00)
{
[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 ((NSInteger)[GIF_pointer length] >= dataPointer + length) // Don't read across the edge of the file..
{
GIF_buffer = [[GIF_pointer subdataWithRange:NSMakeRange(dataPointer, length)] retain];
dataPointer += length;
return YES;
}
else
{
return NO;
}
}

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

- (NSData*) getFrameAsDataAtIndex:(int)index {
if (index < (NSInteger)[GIF_frames count])
{
return ((AnimatedGifFrame *)[GIF_frames objectAtIndex:index]).data;
}
else
{
return nil;
}
}

- (UIImage*) getFrameAsImageAtIndex:(int)index {
NSData *frameData = [self getFrameAsDataAtIndex: index];
UIImage *image = nil;

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

return image;
}


@end


你可能感兴趣的:(ios开发学习相关)