`
修博龙泉
  • 浏览: 318179 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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 <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 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 gif 动画使用

    在iOS开发中,GIF动画的使用已经成为一种常见的需求,特别是在社交、娱乐或者信息展示类应用中。GIF格式因其小巧且支持循环播放的特点,深受开发者喜爱。本篇将详细介绍如何在iOS应用中实现GIF动画的显示。 一、GIF...

    ios 播放gif启动动画Demo

    这些库能够解析并播放GIF文件,提供更便捷的方法在UIImageView上显示GIF动画。 4. **`SDWebImage`库的使用**: `SDWebImage`是一个流行的图片加载库,它不仅支持网络图片的异步加载,还支持GIF显示。要使用`...

    ios应用源码之从gif动画创建一个动态uiimages 对象 2018127

    在iOS开发中,UIImages是展示静态图像的基本类,但有时候我们需要展示动态效果,比如GIF动画。本教程将深入探讨如何从GIF动画中创建一个动态的UIImages对象,适用于iOS应用源码实践。 首先,我们要理解GIF格式的...

    ios-GIF图片的展示.zip

    在iOS平台上,展示GIF图片是一项常见的需求,特别是在创建动态表情、加载指示或者动画效果时。在Xcode 6.2及更高版本中,由于原生SDK并不直接支持GIF格式,开发者通常需要借助第三方库或者自定义解决方案来实现。本...

    IOS使用UIImageView显示gif动画的例子 SDWebImage代码5月修改升级

    为了实现在UIImageView上展示GIF动画,开发者通常会借助第三方库,比如本例中提到的`SDWebImage`。`SDWebImage`是一个非常流行且功能强大的图片加载库,它不仅支持从网络加载图片,还提供了缓存机制和处理各种图片...

    ios-启动图加载gif动画.zip

    总之,通过使用`FLAnimatedImage`库,开发者可以在iOS应用的启动过程中展示GIF动画,提高用户体验。正确集成和管理这个库,以及适时地启动和停止动画,是实现这一功能的关键。同时,结合其他界面元素,如进度条,...

    ios-动画展示gif图片.zip

    在iOS开发中,为了使应用更...通过以上方法,你就可以在iOS应用中完美展示GIF动画了。在实际开发中,还要根据项目需求和性能要求选择最适合的解决方案。同时,不断学习和掌握新的技术和工具,才能不断提升iOS开发技能。

    IOS 显示Gif图片

    在iOS开发中,显示GIF图片是一个常见的需求,特别是在创建社交、娱乐或者信息展示类应用时。GIF是一种流行的动画格式,它支持循环播放和透明度,为用户提供了一种生动的视觉体验。本文将深入探讨如何在iOS应用中实现...

    IOS使用UIImageView显示gif动画的例子修改

    本教程将详细介绍如何在iOS应用中使用UIImageView来展示GIF动画,同时结合SDWebImage和SCGifExample这两个开源库进行实践。 首先,`UIImageView`是苹果提供的一种用于展示静态图片的视图控件。默认情况下,它不支持...

    iOS OC 加载动图(gif)

    在iOS开发中,加载动图(GIF)是常见的需求,特别是在等待数据加载或展示交互效果时。OC(Objective-C)作为苹果平台的主要编程语言之一,虽然原生并不支持GIF,但通过第三方库可以方便地实现GIF的显示。在本话题中...

    加载Gif动画

    在移动应用和网页开发中,GIF...开发者需要根据项目需求和目标平台,选择最佳方案,并进行细致的优化,以实现流畅、高效的GIF动画展示。通过不断学习和实践,你可以更好地掌握这一技能,为用户提供更优质的互动体验。

    iOS-多媒体-播放Gif动画-5SwiftGif

    在iOS开发中,实现Gif动画的播放是一个常见的需求,特别是在多媒体应用中。Gif是一种支持多帧图像的格式,可以用来创建简单的动画效果。在本教程中,我们将重点讨论如何使用Swift语言来处理和播放Gif动画。我们将...

    swift-iOS的完整动画GIF支持

    在标题中提到的“swift-iOS的完整动画GIF支持”很可能是指一个开源库或者方法,它提供了全面的功能来解析和播放GIF动画。 1. **函数**:在实现GIF动画时,我们通常会用到一系列的函数来读取、解析和绘制GIF的每一帧...

    iOS gif 原帧真实播放类库(有Demo)

    总之,这个“iOS gif 原帧真实播放类库(有Demo)”提供了对GIF动画的高效处理,尤其强调了原帧的真实播放,这对于需要高质量GIF体验的应用来说非常关键。通过分析Demo,开发者可以获得关于如何在自己的应用中实现...

    IOS使用UIImageView显示gif动画的例子 SDWebImage5月修改升级

    在这个例子中,我们关注的是如何在UIImageView中展示GIF动画。首先,我们需要导入SDWebImage的相关头文件,包括: 1. UIButton+WebCache.h:扩展UIButton,使其具有加载网络图片的能力。 2. SDWebImageManager.h:...

    超好用的纯代码GIF动画显示控件

    这为跨平台开发提供了便利,无论是在Windows、Linux还是Mac OS,或者是Android、iOS等移动系统,都能实现一致的GIF动画展示效果。 控件的核心特性可能包括: 1. **高效解码**:优化的算法使得GIF文件能快速高效...

    ios-折叠动画.zip

    主要文件有两个:一个名为"折叠.gif"的动画图像,很可能是展示折叠效果的示例;另一个是"a.txt",可能是一份简短的文字说明或代码片段。 首先,让我们深入了解一下iOS中的视图动画。苹果的UIKit框架提供了强大的...

    20个进度条GIF动画

    "20个进度条GIF动画"这个资源包包含的是20种不同的动态进度条图形,这些GIF格式的文件适用于多种场景,如网页设计、软件开发、移动应用或是任何需要显示进度的地方。 首先,我们要理解进度条的基本概念。进度条通常...

    IOS应用源码——从GIF动画创建一个动态UIImages 对象.zip

    在iOS开发中,有时我们需要将GIF动画转换为动态的UIImage对象,以便在我们的应用程序中显示这些动画。这个"IOS应用源码——从GIF动画创建一个动态UIImages 对象.zip"提供了一个实用的解决方案。它包含了一段源代码,...

    IOS应用源码之从GIF动画创建一个动态UIImages 对象 .rar

    在iOS开发中,有时我们需要将GIF动画集成到应用程序中,为用户提供更加丰富的交互体验。这个压缩包文件“从GIF动画创建一个动态UIImages 对象”提供了关于如何在iOS应用中实现这一功能的源码示例。接下来,我们将...

Global site tag (gtag.js) - Google Analytics