美文网首页demoiOS高质量博客Edison
iOS开发--GIF图片的选取,压缩,上传

iOS开发--GIF图片的选取,压缩,上传

作者: 半缘魔君 | 来源:发表于2017-02-22 17:31 被阅读3285次

    之前写了一篇关于PNG/JPEG图片的选取,压缩,上传(下边统一简称前文): http://www.jianshu.com/p/011b5ef47675, 文本依赖前文的UIImage+ZipSizeAndLength分类进行图片的压缩等.
    总结一下: 用原生的 UIImagePickerController 选取图片; 用原生的UIImageJPEGRepresentation()和图形上下文对图片进行压缩; 用AFN进行上传操作.
    好了,总结完之后进入今天的主题-----GIF图片的选取,压缩,上传;


    目录:
    一 前言
    二 选取图片(重点)
    三 获取GIF图片的原始完整二进制数据(重点)
    四 压缩图片(重点)
    五 上传图片


    一 前言

      有的同学会疑惑,难道gif图片不能用前文说的PNG/JPEG图片的方法进行选取,压缩和上传吗?
    

    我可以肯定的给你回答---不能(自己亲身敲代码做的test,如有疑问,欢迎留言)
    原因如下:
    1 前文说的选取图片的代码如下:
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
    UIImage *image = [info objectForKey:@"UIImagePickerControllerEditedImage"];
    }
    对于GIF图片只能选取到第一帧,无法取到所有帧.
    2 无法取到GIF所有帧,就不能对图片进行压缩
    3 无法取到GIF所有帧,也不能将图片转化成二进制数据
    4 没有二进制数据就无法进行上传操作
    所以需要换另外一个方法,具体如下.


    二 选取图片
    首先判断是不是GIF图片,如果是才需要走GIF的逻辑,判断方法有如下两种:

    第一种(比较取巧):
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
    NSString *assetString = [[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
    if([assetString hasSuffix:@"GIF"]){
    //这个图片是GIF图片
    } else {
    }
    }
    第二种:利用iOS9.0以后出的 Photos/Photos.h 里边的API进行判断,代码如下:

    NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
    PHFetchOptions *options = [[PHFetchOptions alloc]init];
    PHFetchResult *set = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:options];
     //转化NSData
    PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];
    PHImageRequestOptions *option = [PHImageRequestOptions new];
    option.resizeMode = PHImageRequestOptionsResizeModeFast;
    option.synchronous = YES;
    PHAsset *asset = set.firstObject;//本文只是选取一张
    [imageManager requestImageDataForAsset:asset
                   options:option
             resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                     if ([dataUTI isEqualToString:(__bridge NSString *)kUTTypeGIF]) {
                          //这个图片是GIF图片
                          }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypePNG]){
                                NSLog(@"PNG图片");
                          }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG]){
                                NSLog(@"JPEG图片");
                          }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG2000]){
                                NSLog(@"JPEG2000图片");
                          }else {
                          }
    }];
    

    本文用的是第一种(比较简单,效率高)


    三 获取GIF图片的原始完整二进制数据(所有帧)
    代码如下:

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {      
       NSString *assetString = [[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
       if([assetString hasSuffix:@"GIF"]){
           //这个图片是GIF图片
           ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc]init];
           [assetLibrary assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
            ALAssetRepresentation *re = [asset representationForUTI:(__bridge NSString *)kUTTypeGIF];;
            NSUInteger size = (NSUInteger)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];//这个就是选取的GIF图片的原二进制数据
            free(buffer);
            } failureBlock:^(NSError *error) {
            
        }];
        } else {
       }
    }
    

    四 压缩图片

    利用CoreGraphics/CoreGraphics.h API转换GIF图片并再次转成符合要求的图片的二进制文件:
    封装方法如下:
    + (NSData *)zipGIFWithData:(NSData *)data {
    if (!data) {
    return nil;
    }
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    size_t count = CGImageSourceGetCount(source);
    UIImage *animatedImage = nil;
    NSMutableArray *images = [NSMutableArray array];
    NSTimeInterval duration = 0.0f;
    for (size_t i = 0; i < count; i++) {
    CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
    duration += [self frameDurationAtIndex:i source:source];
    UIImage *ima = [UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
    ima = [ima zip];
    [images addObject:ima];
    CGImageRelease(image);
    if (!duration) {
    duration = (1.0f / 10.0f) * count;
    }
    animatedImage = [UIImage animatedImageWithImages:images duration:duration];
    }
    CFRelease(source);
    return UIImagePNGRepresentation(animatedImage);
    }
    将三种得到的gif图片的二进制数据精心压缩:
    代码如下:

     ....
    NSData *data = [NSData dataWithBytes:buffer length:bytes];//这个就是选取的GIF图片的原二进制数据
    data = [self zipGIFWithData:data];
    //上传二进制数据
    

    五 上传图片,与前文上传图片一样

    相关文章

      网友评论

      • 跬步千里_LenSky:怎么我用压缩以后的图片得不到动态图而是一张静态的呢,希望解答一下问题
        半缘魔君:@跬步千里_LenSky 压缩以后需要先存到本地,然后读出来二进制,再上传
        跬步千里_LenSky:@半缘魔君 是的
        半缘魔君:不压缩是动态的吗?
      • SharsBin:您好 你这个 比如 我5 m的gif 想压缩到 2m 这个在哪里可以设置
        打豆豆_2e20:UIImagePNGRepresentation(animatedImage) 图片又变成了第一帧了,这个问题你解决了吗
        SharsBin:@半缘魔君 其实不用压缩
        半缘魔君:http://www.jianshu.com/p/011b5ef47675 这篇文章里的 zip 方法里的 compressToByte:2*1024*1024
      • Seeulater:这种判断是不是gif图的方式还是有点问题 ,应该用 [(ALAsset *)result.defaultRepresentation.metadata objectForKey:@"{GIF}"] 这种方式去判断才可以,放置有些图片后缀名是和实际图片类型不一致的情况
        半缘魔君:恩,你这种情况我考虑过,只不过一般在修改后缀名时,会认为图片格式发生变化,暂时就没有管这种情况了;
        如果有需求可以兼容一下,还是不错的
        另外在上传的时候也需要注意这种情况
        感谢提出宝贵意见
      • CGPointZero:求源码和那个[ima zip];方法!
        CGPointZero:@半缘君换 确实可以压缩gif,但是压缩后,图片尺寸变得很小
        半缘魔君:如本篇文章没有,请看上篇http://www.jianshu.com/p/011b5ef47675, [ima zip]方法在上一篇里
        半缘魔君:源码全部都在文章中,
      • de8669f11389: return UIImagePNGRepresentation(animatedImage);
        这不是返回的是PNG类型的图吗
        半缘魔君:@堃木 目前GIF图片的压缩的思路就是,每张图片进行压缩,然后再生成GIF,没有办法直接压缩
        de8669f11389:@半缘君换 哦哦 我转换了,传给服务器说我这不是gif的数据,我就很迷惑了。
        半缘魔君:这个是二进制数据,上传的时候需要的
      • c19dfb62786e:另外取到了phasset怎么转成nsdata上传呢:sob:
        半缘魔君:PHAsset *asset = set.firstObject;//本文只是选取一张
        [imageManager requestImageDataForAsset:asset
        options:option
        resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
        if ([dataUTI isEqualToString:(__bridge NSString *)kUTTypeGIF]) {
        //这个图片是GIF图片
        }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypePNG]){
        NSLog(@"PNG图片");
        }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG]){
        NSLog(@"JPEG图片");
        }else if([dataUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG2000]){
        NSLog(@"JPEG2000图片");
        }else {
        }
        }];
        block 里的imageData就是PHAsset对应的NSData
      • c19dfb62786e:判断gif的第一种方法跟那个filename contain @“GIF”都一样吧?另外用这种方法会有可能被拒吗、
        第二种主要有个耗时,在纠结用哪个
        半缘魔君:可以啊,不会被拒吧,有没有调用私有API
      • 4ea6dd2fba9c:楼主您好,求您的帮助。
        NSData *imgData = UIImageJPEGRepresentation(self, 0.5);
        NSLog(@"压缩后%ld ", imgData.length); // 87564 --例
        UIImage *newImage = [UIImage imageWithData: imgData];
        NSData *newImgData = UIImageJPEGRepresentation(newImage, 1);
        NSLog(@"转换后%ld ", newImgData.length); //2345678 --例
        这样看来,UIImageJPEGRepresentation这东西真的能压缩图片吗?
        我试过把newImage写入文件,查看文件属性和压缩后大小一致,没问题,再读取这个文件,data还是很大。GIF压缩必然经过每一帧的处理再合成,所以UIImageJPEGRepresentation根本没有任何用处,只能靠调整像素尺寸来减少大小。求解作者,我是不是走入什么误区了?还是有什么其他方法可以使用,研究了两天了,希望能得到您的指点,谢谢。
        半缘魔君:NSData *imgData = UIImageJPEGRepresentation(self, 0.5);
        NSLog(@"压缩后%ld ", imgData.length); // 87564 --例
        UIImage *newImage = [UIImage imageWithData: imgData];
        NSData *newImgData = UIImageJPEGRepresentation(newImage, 1);
        NSLog(@"转换后%ld ", newImgData.length); //2345678 --例

        根据你的打印结果,猜测UIImageJPEGRepresentation方法压缩是可逆的,也就是说
        NSData *imgData = UIImageJPEGRepresentation(self, 0.5); 这一步确实压缩了,但是UIImageJPEGRepresentation(newImage, 1);调用后可以获取到原图片(可以对比一下原图的大小)
      • 胡浩三雄:[self frameDurationAtIndex:i source:source]
        ima = [ima zip];
        这些方法请问下怎么写的?
        半缘魔君:@小绵羊hzh SD里边的这个分类,你看看UIImage+GIF
        小绵羊hzh:@半缘魔君 [self frameDurationAtIndex:i source:source]这个方法SDWebImage里没有啊
        半缘魔君:第一个方法是SD里边的;第二个参看我封装的UIImage+ZipSizeAndLength
      • iOSTNP:学习学习 但是我写的没有这么麻烦
        半缘魔君:@iOSTNP 这个主要都没事,最主要的是写明白,大家能看懂就行:smiley:
        iOSTNP:@半缘君换 我写的太随便了 还是楼主写的详细
        半缘魔君:你的是怎么做的呢,欢迎留言交流.
      • 五蕴盛:不错, mark, 学习了:+1:
        半缘魔君:有任何问题欢迎留言交流:smile:

      本文标题:iOS开发--GIF图片的选取,压缩,上传

      本文链接:https://www.haomeiwen.com/subject/lmdmwttx.html