2016-01-04 20:49:29 jeffasd 阅读数 4093

通过路径转成data数据,写入本地相册就行了:

NSData *data = [NSData dataWithContentsOfFile:path];
        // 保存到本地相册
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
        [library writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
            NSLog(@"Success at %@", [assetURL path] );
        }] ; 

2017-12-25 10:08:10 qq_34210988 阅读数 3001

前言:

今日,需求要求保存一个gif动态图.原理比较简单.但是中间触发了一些问题.和概念在这里给大家分享一下

动态图

GIF.WEBP.APNG 三者区别我这里暂不讨论.不是专业的所以深究下去会有很多东西需要吸收

iOS动态图保存

iOS相册支持GIF 和APNG 的保存 目测iOS11.0在相册中也可以播放GIF 的动态图.而iOS8.3不能.
writeImageDataToSavedPhotosAlbum 可以直接将其写入相册
UIImageWriteToSavedPhotosAlbum() 图像强制转码为PNG

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.gifUrl]];
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error){
            dispatch_async(dispatch_get_main_queue(), ^{
                [gifAnimation stop]
                if (!error) {
                    [YToast showToast:@"下载成功"];
                }else
                    [YToast showToast:@"下载失败"];
             });
    }];
});
//iOS9.0以前调用ALAssetsLibrary 来存储图片Data
//iOS9.0以后如下PHPhotoLibrary
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.gifUrl]];
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        [[PHAssetCreationRequest creationRequestForAsset] addResourceWithType:PHAssetResourceTypePhoto data:data options:nil];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [gifAnimation stop]
            if(success && !error){
                [YToast showToast:@"下载成功"];
            }else
                [YToast showToast:@"下载失败"];
        });
    }];
});

亲测应该是没有什么问题的! 但是很少用dataWithContentsOfURL 来获取data了,我尝试着用NSURLSessionDownloadTask进行下载GIF 然而问题就出来了..我没办法在回调中获取data只能讲文件保存到一个沙盒路径中.我也没办法获取他的progress 虽然他给了这个出口可以拿到.因为我还有下载的这个过程.相当于没有将图片写进相册.那问题就来了.怎么获得写入相册的progress 以及我怎么获得task下载的data而不是直接的文件.目前网上没有找到更好的解决方法!如果有志同道合的朋友知道.请联系我!

2017-03-23 14:01:40 vkooy 阅读数 5942

大家都知道iOS的系统相册是不支持gif图片预览的。但是,这并不代表系统相册不能保存和读取gif图片。通过Safari长按gif图片,选择保存到相册,这时保存到相册里的图片就是gif的,虽然它不会动。
下面将介绍如何对系统相册进行gif的读取与保存。

什么是 UTI

iOS系统相册是根据 UTI 来区分资源类型的。那什么是 UTI呢。UTI字面意思是:Uniform Type Identifiers(统一类型标示符)
apple 介绍文档:

https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Introduction/Introduction.html

都支持哪些UTI类型:

https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html#//apple_ref/doc/uid/TP40009259-SW1

在 MobileCoreServices/UTCoreTypes.h中可以找到一些内置的UTI类型

extern const CFStringRef kUTTypeImage                                __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeJPEG                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeJPEG2000                             __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeTIFF                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypePICT                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeGIF                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypePNG                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeQuickTimeImage                       __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeAppleICNS                            __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeBMP                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeICO                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
extern const CFStringRef kUTTypeRawImage                             __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);
extern const CFStringRef kUTTypeScalableVectorGraphics               __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);
extern const CFStringRef kUTTypeLivePhoto                            __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_9_1);

用来标识 gif 资源的,就是 kUTTypeGIF 这个类型,实际字符串是:@"com.compuserve.gif"

判断是不是 gif 资源

我们使用 ALAssetsLibrary 来进行相册资源的获取。至于如何使用ALAssetsLibrary,这不是本文的重点,大家搜索一下即可。

定义一个ALAsset的类别。下面所有的实例方法均是这个类别中的方法

@interface ALAsset (GifSupport)
@end
@implementation ALAsset (GifSupport)
@end

判断是不是一个gif资源,只要简单的判断资源在 kUTTypeGIF 这个UTI下是不是有内容就可以了。

- (BOOL)isGif
{
    ALAssetRepresentation *re = [self representationForUTI: (__bridge NSString *)kUTTypeGIF];
    if (re) {
        return YES;
    }
    return NO;
}

读取 gif 数据

一个ALAsset 是gif资源,那么通过普通的获取 CGImageRef 是无法取到完整的gif的,只能取到第一帧。
所以需要使用 ALAssetRepresentation 的这个方法来获取 data 

- (NSUInteger)getBytes:(uint8_t *)buffer fromOffset:(long long)offset length:(NSUInteger)length error:(NSError **)error

下面是具体实现

- (NSData *)gifData
{
    if (![self isGif]) {
         return nil;
    }

    ALAssetRepresentation *re = [self representationForUTI:(__bridge NSString *)kUTTypeGIF];;  
    long long size = re.size;
    uint8_t *buffer = malloc(size);
    NSError *error;
    NSUInteger bytes = [re getBytes:buffer fromOffset:0 length:size error:&error];
    NSData *data = [NSData dataWithBytes:buffer length:bytes];
    free(buffer);
    return data;
}

展示 gif 图片

使用SDWebImage中 UIImage+GIF.h 内的一个类方法即可将gif data转换成 UIImage

+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;

简单的展示:

- (void)printGifImage
{
    NSData *data = [self gifData];
    UIImage *gifImage = [UIImage sd_animatedGIFWithData:data];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:gifImage];
    imageView.frame = CGRectMake(0, 0, gifImage.size.width, gifImage.size.height);
    [[[UIApplication sharedApplication] keyWindow] addSubview:imageView];
}

保存 gif 图片到相册

我们自己的应用可不可以实现Safari里面的保存gif功能呢?
答案是可以的。
这一部分比较复杂,直接上代码。里面没有做具体的异常判断。需要根据需求自行添加。
我将在系统相册里建立一个gif相册,gif图片将保存到这个组里面。

测试时用了 [self gifData] 作为待保存的data。实际上可以使用 SDWebImage的缓存等等具体gif数据

- (void)saveGifData:(NSData *)data toGroup:(ALAssetsGroup *)group inLibrary:(ALAssetsLibrary *)library
{
    NSDictionary *metadata = @{@"UTI":(__bridge NSString *)kUTTypeGIF};
    // 开始写数据   
    [library writeImageDataToSavedPhotosAlbum:data metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error) {

        if (error) {
            NSLog(@"写数据失败:%@",error);
        }else{

            [library assetForURL:assetURL resultBlock:^(ALAsset *asset) {

                NSLog(@"成功保存到相册");

                if ([group isEditable]) {
                    [group addAsset:asset];
                }else{
                    NSLog(@"系统gif相册不可编辑或者为nil");
                }

            } failureBlock:^(NSError *error) {
                NSLog(@"gif保存到的ALAsset有问题, URL:%@,err:%@",assetURL,error);
            }];
        }
   }];
}









2017-02-07 17:28:54 broadview2006 阅读数 1951

引言:GIF图像格式是常见的一种动态图片格式,无论是在Web端还是在移动端都经常遇到,但是考虑目前iOS还无法原生展现GIF图片,而对于GIF的原生支持暂时也没有像JPG、PNG等图像格式支持得这么全面,因此本文从图片的合成与分解角度来为大家讲解GIF的知识,结合ImageIO框架可以更方便地实现GIF图片的合成与分解。 
本文选自《iOS动画——核心技术与案例实战》。

GIF在iOS中的使用场景

  GIF在iOS中的使用场景有以下三个方面。 
(1)GIF图片分解为单帧图片。 
(2)一系列单帧图片合成GIF图片。 
(3)iOS系统上展示GIF动画效果。 
  在GIF的合成和分解方面将会接触到iOS图像处理核心框架ImageIO,作为iOS系统中图像处理的核心框架,它为我们提供了各种丰富的API,本文将要实现的GIF分解与合成功能,通过ImageIO就可以很方便地实现。GIF动画展示效果将结合UIImageView和定时器,利用逐帧展示的方式为大家呈现GIF动画效果。

GIF分解单帧图片

1 GIF图片分解过程

  GIF分解为单帧图片的过程如下。 
图片描述
  整个过程划分为5个模块、4个过程,分别如下。 
(1)本地读取GIF图片,将其转换为NSdata数据类型。 
(2)将NSData作为ImageIO模块的输入。 
(3)获取ImageIO的输出数据:UIImage。 
(4)将获取到的UIImage数据存储为JPG或者PNG格式保存到本地。 
  在整个GIF图片分解的过程中,ImageIO是处理过程的核心部分。它负责对GIF文件格式进行解析,并将解析之后的数据转换为一帧帧图片输出。幸运的是我们并不是“轮子”的创造者,而是只要使用轮子即可。所以在本书中我们不去研究GIF分解合成算法的具体实现方式,而是将注意力聚焦在如何使用ImageIO框架实现需要的功能上。

2 GIF图片分解代码实现

  在正式分析代码之前,先来看看整个工程的文件结构,如图。 
【图2】
  源文件使用的是plane.gif文件。ViewController.swift文件中的viewDidLoad()方法中包含了GIF图片分解为单帧图片并保存到本地的所有代码。下面就结合“GIF分解为单帧图片的过程”来实现这一功能。 
功能模块一:读取GIF文件并将之转换为NSdata类型。

1   let gifPath:NSString = Bundle.main.path(forResource: "plane", ofType: "gif")! as NSString
2   let gifData:Data = try! Data(contentsOf: URL(fileURLWithPath: gifPath as String))

  代码第1行通过path方法获取文件名为plane、文件格式为gif的文件地址。第2行获取文件信息并加载到gifData(NSData类型)变量中。至此已经完成整个处理流程的第一个环节。 
【图3】
  功能模块二:利用ImageIO框架,遍历所有GIF子帧。需要注意的是使用ImageIO必须把读取到的NSdata数据转换为ImageIO可以处理的数据类型,这里使用CGImageSourceRef实现。其相应功能模块的处理流程如下所示。 
【图4】

1   let gifDataSource:CGImageSource =
           CGImageSourceCreateWithData(gifData as CFData, nil)!
2   let gifImageCount:Int = CGImageSourceGetCount(gifDataSource)
3     for i in 0...gifImageCount-1{
            let imageref:CGImage? =CGImageSourceCreateImageAtIndex(gifDataSource, i, nil)
            let image:UIImage = UIImage(cgImage: imageref!,scale:UIScreen.main.scale,orientation:UIImageOrientation.up )
        }

  下面是GIF数据处理流程中ImageIO部分功能描述。代码第1行实现将GIF原始数据类型NSdata转换为ImageIO可以直接处理的数据类型CGImageSourceRef。第2行获取当前GIF图片的分帧个数。我们知道GIF图片都是由一帧帧图片组成的,那么这一行就是为了获取构成GIF图片的张数。第3行对CGImageSource数据按照图片的序号进行遍历,将遍历出的结果使用UIImage系统方法将之转换为UIImage。 
  这里重点为大家介绍两种方法。 
  CGImageSourceCreateImageAtIndex方法的作用是返回GIF中其中某一帧图像的CGImage类型数据。该方法有三个参数,参数1为GIF原始数据,参数2 为GIF子帧中的序号(该序号从0开始),参数3为GIF数据提取的一些选择参数,因为这里不是很常用,所以设置为nil。

public func CGImageSourceCreateImageAtIndex(_ isrc: CGImageSource, _ index: Int, _ options: CFDictionary?) -> CGImage?

  以下为UIImage类的方法,这个方法用于实例化UIImage实例对象。该方法有三个参数,参数1为需要构建UIImage的内容,注意这里的内容是CGImage类型,参数2为手机物理像素与手机和手机显示分辨率的换算系数,参数3表明构建的UIImage的图像方向。通过这个方法就可以在某种手机分辨率下构建指定方向的图像,当然图像的类型是UIImage类型。

public init(CGImage cgImage: CGImage, scale: CGFloat, orientation: UIImageOrientation)

  通过上述两步已经获取了UIImage,然而UIImage并不是通常我们看到的图像格式,此图像格式最大的特点是无法存储为本地可以查看的图片格式,因此如果需要将图像保存在本地,就需要在这之前将已经得到的UIImage数据类型转换为PNG或者JPG类型的图像数据,然后才能把图像存储到本地。 
  下面是完整的GIF图像分解保存代码:

override func viewDidLoad() {
1        super.viewDidLoad()
2        let gifPath:NSString = Bundle.main.path(forResource:"plane", ofType: "gif")! as NSString
3        let gifData:Data = try! Data(contentsOf:URL(fileURLWithPath: gifPath as String))
4        let gifDataSource:CGImageSource =CGImageSourceCreateWithData(gifData as CFData, nil)!
5        let gifImageCount:Int =CGImageSourceGetCount(gifDataSource)
6        for i in 0...gifImageCount-1{
7            let imageref:CGImage? =CGImageSourceCreateImageAtIndex(gifDataSource, i, nil)
8            let image:UIImage = UIImage(cgImage: imageref!,scale:UIScreen.main.scale,orientation:UIImageOrientation.up )
9            let imageData:Data = UIImagePNGRepresentation(image)!
10           var docs=NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
11           let documentsDirectory = docs[0] as String
12           let imagePath = documentsDirectory+"/\(i)"+".png"
13           try? imageData .write(to: URL(fileURLWithPath:imagePath), options: [.atomic])
14           print("\(imagePath)")

        }
    }

  代码第1行使用UIImagePNGRepresentation方法将UIImage数据类型存储为PNG格式的data数据类型,第2行代码和第3行代码获取应用的Document目录,第4行调用write方法将图片写入到本地文件中。如果大家想查看最终写入的效果,可以在最后一行添加print信息,将文件写入路径打印出来,观察图像写入是否成功。

3 GIF图片分解最终实现效果

  通过上述代码中的最后一行print(“(imagePath)”)可以获取图片最终保存的路径。进入该路径下可以看到下图所示的图片最终分解结果。 
【图5 图6】

  根据上下图,在Mac系统下,利用系统图片的查看工具来查看GIF图片的分帧结果,对比图中内容,可以看出GIF图片分解的结果是正确的。 
图片描述

序列图像合成GIF图像

1 GIF图片合成思路

  多帧图像合成GIF的过程和GIF分解多帧图像的过程互逆,GIF图片分解过程倒过来推,就是GIF图像合成的过程。这里将上面分解的67张序列单帧图像作为需要处理的输入源进行讲述。 
  从功能上来说,GIF图片的合成分为以下三个主要部分。 
(1)加载待处理的67张原始数据源。 
(2)在Document目录下构建GIF文件。 
(3)设置GIF文件属性,利用ImageIO编码GIF文件。

2 GIF图片合成代码实现

  如下代码是根据GIF构建的三个主要步骤进行编写的。第一部分代码的功能是将67张PNG图片读取到NSMutableArray数组中。代码第1行初始化可变数组,第2行遍历67张本地图片,第3行按照图片的命名规律,构建67张图片名称,第4行加载本地图片。最后一行将读取的图片依次加载到images可变数组中。

        // Part1:读取67张png图片
1        let images:NSMutableArray = NSMutableArray()
2        for i in 0...66{// 遍历本地67张图片
3            let imagePath = "\(i).png" // 构建图片名称
4            let image:UIImage = UIImage(named: imagePath)!//
5            images.addObject(image)// 将图片添加到数组中}

  代码第二部分的功能是构建在Document目录下的GIF文件路径。具体实现如下所示。

        // Part2:在Document目录创建gif文件
1      var docs=NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
2      let documentsDirectory = docs[0] as String
3      let gifPath = documentsDirectory+"/plane.gif"
4      print("\(gifPath)")
5      let url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, gifPath as CFString!,CFURLPathStyle.cfurlposixPathStyle, false)
6     let destion = CGImageDestinationCreateWithURL(url!, kUTTypeGIF, images.count, nil)

  代码1一行和第2行获取Document路径地址,第3行代码通过字符串拼接时组成完整的Document路径下plane.gif文件路径。为了方便查看GIF文件所在路径,第4行代码将GIF文件路径打印出来。第5行代码将plane.gif文件路径由string类型转换为URL类型。最后一行代码是ImageIO中构建GIF图片非常重要的方法,我们重点来分析该方法的作用和功能。

public func CGImageDestinationCreateWithURL(_ url: CFURL, _ type: CFString, _ count: Int, _ options: CFDictionary?) -> CGImageDestination?

CGImageDestinationCreateWithURL方法的作用是创建一个图片的目标对象,为了便于大家理解,这里把图片目标对象比喻为一个集合体。 
CGImageDestination结构
                      CGImageDestination结构 
  集合体中描述了构成当前图片目标对象的一系列参数,如图片的URL地址、图片类型、图片帧数、配置参数等。本代码中将plane.gif的本地文件路径作为参数1传递给这个图片目标对象,参数2描述了图片的类型为GIF图片,参数3表明当前GIF图片构成的帧数,参数4暂时给它一个空值。 
  到目前为止,待处理图片源已经加载到代码中,GIF图片Destination也已经完成构建,下面就需要使用ImageIO框架把多帧PNG图片编码到GIF图片中,其处理流程如下。 
【图8】
  具体实现代码如下:

 // Part3:设置gif图片属性,利用67张png图片构建gif
1    let cgimagePropertiesDic = [kCGImagePropertyGIFDelayTime as String:0.1]//设置每帧之间播放时间
2    let cgimagePropertiesDestDic =[kCGImagePropertyGIFDictionary as String:cgimagePropertiesDic];
3    for cgimage in images{
4            CGImageDestinationAddImage(destion!, (cgimage as AnyObject).cgImage!!,cgimagePropertiesDestDic as CFDictionary?);}// 依次为gif图像对象添加每一帧元素
5    let gifPropertiesDic:NSMutableDictionary =NSMutableDictionary()
6    gifPropertiesDic.setValue(kCGImagePropertyColorModelRGB,forKey: kCGImagePropertyColorModel as String)
7    gifPropertiesDic.setValue(16, forKey:kCGImagePropertyDepth as String)// 设置图像的颜色深度
8    gifPropertiesDic.setValue(1, forKey:kCGImagePropertyGIFLoopCount as String)// 设置Gif执行次数
9    let gifDictionaryDestDic = [kCGImagePropertyGIFDictionary as String:gifPropertiesDic]
10   CGImageDestinationSetProperties(destion!,gifDictionaryDestDic as CFDictionary?);//为gif图像设置属性
11   CGImageDestinationFinalize(destion!);

  代码第1行设置GIF图片属性,设置当前GIF中每帧图片展示时间间隔为0.1s。代码第2行构建一个GIF图片属性字典,字典使用GIF每帧之间的时间间隔初始化。代码第4行使用遍历的方法将已经准备好的图片快速追加到GIF图片的Destination中。代码第5行初始化一个可变字典对象,该字典对象主要用于设置GIF图片中每帧图片属性。第6行设置图片彩色空间格式为RGB(Red Green Blue三基色)类型。第7行设置图片颜色深度。一般来说黑白图像也称为二值图像,颜色深度为1,表示2的一次方,即两种颜色:黑和白。灰度图像一般颜色深度为8,表示2的8次方,共计256种颜色,即从黑色到白色的渐变过程有256种。对于彩色图片来说一般有16位深度和32位深度之说,这里设置为16位深度彩色图片。代码第8行设置GIF图片执行的次数,这里设置为执行一次。代码第9行和第10行负责将以上图片设置的各种属性添加到GIF的Destination目标中。最后一行完成GIF的Destination目标文件构建。 
  可以打印出当前GIF图片的路径,在该路径下可以看到最终生成的GIF图片。 
【图9】

Gif图像展示

  iOS原生并不支持直接显示GIF图片,由前面的分析可知,GIF图片由一帧帧的单帧图片构成,所以只要实现GIF图片的分解,接下来就是多组图片显示的问题了。为大家介绍另外一种图片展现形式,即基于UIImageView展现GIF多帧图片。 
经过对GIF图片展示思路的分析可以知道,在iOS下展现GIF分为两步:第一步分解GIF图片为单帧图片,第二步在iOS下展现多帧图片。UIImageView是一个用来展现图片的UI组件,不过它还有一些动画属性可以用来进行逐帧动画展现。 
考虑到第一步GIF图片已经分解,所以这里把分解之后的67张图片先加载进来。 
【图10】
  UIImageView多帧图像展示具体实现代码如下。

1       var images:[UIImage] = []
2        for i in 0...66{// 遍历本地67张图片
3            let imagePath = "\(i).png" // 构建图片名称
4            let image:UIImage = UIImage(named: imagePath)!
5            images.append(image)// 将图片添加到数组中
        }
6        let imageView = UIImageView()
7        imageView.frame = self.view.bounds
8        imageView.contentMode = UIViewContentMode.Center
9        self.view.addSubview(imageView)
10       imageView.animationImages = images
11       imageView.animationDuration = 5
12       imageView.animationRepeatCount = 1
13       imageView.startAnimating()

  代码第1行初始化一个子元素为UIImage类型的数组对象。第2行到第5行通过for循环将67张图片依次加载到当前数组中。第6行实例化一个UIImageView实例对象。第7行和第8行设置UIImageView实例对象的frame位置属性以及图片的拉伸方式,这里设置为居中显示。第9行将UIImageView添加到self.view图层上。第10行将初始化加载的67张图片添加到UIImageView实例的animationImages上,相当于设置UIImageView的内容。第11行设置UIImageView图片动画播放周期。第12行设置动画重复次数。最后一行启动UIImageView多帧图片展示动画。 
【图11】
  本文选自《iOS动画——核心技术与案例实战》,点此链接可在博文视点官网查看此书。

                 

图片描述

  想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。
                       图片描述

2019-08-12 13:57:53 qq_30356665 阅读数 462

iOS系统提供的UIImageView控件是不支持GIF的加载的,在APP开发中会使用到一些GIF图片,本文主要讲解苹果手机上GIF图使用方法,主要是基于SDWebImage框架。

一、界面显示:

1.先集成SDWebImage及SDWebImage/GIF框架

pod 'SDWebImage'

pod 'SDWebImage/GIF'

2.使用SDWebImage/GIF框架提供的兼容GIF图的控件FLAnimatedImageView

  • 初始化

        _img = [[FLAnimatedImageView alloc] init];

        _img.contentMode = UIViewContentModeScaleAspectFill;

        _img.clipsToBounds = YES;

        _img.backgroundColor = ColorViewBack;

        [self.contentView addSubview:_img];

        [_img makeConstraints:^(MASConstraintMaker *make) {

            make.left.right.top.bottom.equalTo(self);

        }];

  • 加载GIF图

   [_img sd_setImageWithURL:[NSUrl urlWithStrint:@"http;xxxxxxx"]

该控件的使用方法与系统的UIImageView一样。

二、上传

上传方法可以分为Base64和file方法,本文主要介绍Base 64方法

//图片文件转化成Base64字符

+(NSString *)getGifBase64Str:(NSData *)data

{

    NSString *imageStyle = [self getImageStyle:data];

    NSString *str = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

    str = [NSString stringWithFormat:@"data:image/%@;base64,%@", imageStyle, str];

    return str;

}

//获取图片的格式

+(NSString *)getImageStyle:(NSData *)data

{

    uint8_t c;

    [data getBytes:&c length:1];

    switch (c) {

        case 0xFF:

            return @"jpeg";

        case 0x89:

            return @"png";

        case 0x47:

            return @"gif";

        case 0x49:

        case 0x4D:

            return @"tiff";

        case 0x52:

            if ([data length] < 12) {

                return nil;

            }

            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];

            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {

                return @"webp";

            }

            return nil;

    }

    return nil;

}

把这个转化后的Base64字符串,当成一个网络请求的参数,发起请求即可(要有post请求,Base64字符长度较大,get请求不支持)

三、保存到相册

NSData *gifData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url] options:NSDataReadingUncached error:nil];

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    NSDictionary *metadata = @{@"UTI":(__bridge NSString *)kUTTypeGIF};

    [library writeImageDataToSavedPhotosAlbum:gifData metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error) {

        [self showAlert:@"保存成功" type:AlertViewType_Toast];

    }] ;

 

  • 以上代码纯手工码出来的,有问题请及时反馈给作者,有不清楚的也可找作者私聊(QQ171080857)

iOS 视频转gif

阅读数 2056

iOS制作演示gif

阅读数 0