GIF图片的问题汇总(类型判断、压缩、保存到相册)

使用GIF图片一般场景是:使用手机相册的GIF图片并上传到某个地方,或者是将浏览到的GIF图片保存到手机相册。这边会涉及到

  • GIF类型判断
  • GIF压缩
  • GIF保存到相册
GIF类型判断

关于图片类型的判断,网上一搜就有很多了,这就直接放代码了:

extension Data{
    
    enum ImageFormat {
        case Unknow
        case JPEG
        case PNG
        case GIF
        case TIFF
        case WebP
        case HEIC
        case HEIF
    }
    var fitSampleCount:Int{
        guard let imageSource = CGImageSourceCreateWithData(self as CFData, [kCGImageSourceShouldCache: false] as CFDictionary) else {
            return 1
        }
        
        let frameCount = CGImageSourceGetCount(imageSource)
        var sampleCount = 1
        switch frameCount {
        case 2..<8:
            sampleCount = 2
        case 8..<20:
            sampleCount = 3
        case 20..<30:
            sampleCount = 4
        case 30..<40:
            sampleCount = 5
        case 40..= 12:
            if let str = String(data: self[0...11], encoding: .ascii), str.hasPrefix("RIFF"), str.hasSuffix("WEBP") {
                return .WebP
            }
        case [0x00] where self.count >= 12:
            if let str = String(data: self[8...11], encoding: .ascii) {
                let HEICBitMaps = Set(["heic", "heis", "heix", "hevc", "hevx"])
                if HEICBitMaps.contains(str) {
                    return .HEIC
                }
                let HEIFBitMaps = Set(["mif1", "msf1"])
                if HEIFBitMaps.contains(str) {
                    return .HEIF
                }
            }
        default: break;
        }
        return .Unknow
    }
    
}

上面是data的扩展来判断图片类型,可是如何拿到UIImage的data这里就有点小坑了。
1、拿到相册图片的data,需要用到PHAsset
这里我用了TZImagePickerController这个三方图片选择器了

func imagePickerController(_ picker: TZImagePickerController!, didFinishPickingPhotos photos: [UIImage]!, sourceAssets assets: [Any]!, isSelectOriginalPhoto: Bool) {
                
        //获取图片资源
        for (index,image) in assets.enumerated() {
            let myAsset = image as? PHAsset
            let options = PHImageRequestOptions()
            options.resizeMode = .fast
            options.isSynchronous = true
            let imageManager = PHCachingImageManager()
            imageManager.requestImageData(for: myAsset ?? PHAsset(), options: options) { (data, dataUti, orientation, info) in
                
                if data?.imageFormat != .GIF {
                    //普通图片
                }else {
                    //GIF图片
                }
                
            }
        }
    }

2、拿到网络图片或者APP沙盒路径下的图片data
网络图片:

do {
            //网络图片
            let data = try Data.init(contentsOf: URL(string: "imageUrl")!)
            //本地图片
//            let data = try Data.init(contentsOf: URL(fileURLWithPath: "imagePath"))
            if data.imageFormat != .GIF {
                //普通图片
            }else {
                //GIF图片
            }
        } catch let error as NSError {

        }
GIF压缩

基本思路就是先抽帧,减少图片的张数。再对剩下的图片进行压缩、编码。合成。

    let sampleCount = data.fitSampleCount
    if let resultData = compressImageData(data, sampleCount: sampleCount){
                print(resultData)
         } else {
                
      }
    /// 同步压缩图片抽取帧数
    ///
    /// - Parameters:
    ///   - rawData: 原始图片数据
    ///   - sampleCount: 采样频率,比如 3 则每三张用第一张,然后延长时间
    /// - Returns: 处理后数据
    func compressImageData(_ rawData:Data, sampleCount:Int) -> Data?{
        guard let imageSource = CGImageSourceCreateWithData(rawData as CFData, [kCGImageSourceShouldCache: false] as CFDictionary),
            let writeData = CFDataCreateMutable(nil, 0),
            let imageType = CGImageSourceGetType(imageSource) else {
                return nil
        }
        
        // 计算帧的间隔
        let frameDurations = imageSource.frameDurations
        
        // 合并帧的时间,最长不可高于 200ms
        let mergeFrameDurations = (0.. Double{
        var frameDuration = Double(0.1)
        guard let frameProperties = CGImageSourceCopyPropertiesAtIndex(self, index, nil) as? [AnyHashable:Any], let gifProperties = frameProperties[kCGImagePropertyGIFDictionary] as? [AnyHashable:Any] else {
            return frameDuration
        }
        
        if let unclampedDuration = gifProperties[kCGImagePropertyGIFUnclampedDelayTime] as? NSNumber {
            frameDuration = unclampedDuration.doubleValue
        } else {
            if let clampedDuration = gifProperties[kCGImagePropertyGIFDelayTime] as? NSNumber {
                frameDuration = clampedDuration.doubleValue
            }
        }
        
        if frameDuration < 0.011 {
            frameDuration = 0.1
        }
        
        return frameDuration
    }
    
    var frameDurations:[Double]{
        let frameCount = CGImageSourceGetCount(self)
        return (0..
GIF保存到相册

系统提供了一个直接将图片写入到相册的方法,但是GIF写入到相册后就变成静态图片了

UIImageWriteToSavedPhotosAlbum(_ image: UIImage, _ completionTarget: Any?, _ completionSelector: Selector?, _ contextInfo: UnsafeMutableRawPointer?)

想要把GIF完整保存到相册就需要用到下面这个方法了:

open class func creationRequestForAssetFromImage(atFileURL fileURL: URL) -> Self?

具体写法:

import AssetsLibrary
import Photos

//GIFFileUrl 为图片沙盒路径,所以要将图片先存放在沙盒路径中。
PHPhotoLibrary.shared().performChanges({
                    PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: URL(fileURLWithPath: GIFFileUrl))
                }) { (success, error) in
                    
                }

技术有限,哪里有问题的话,欢迎指出(部分代码来自网上,侵权删)

你可能感兴趣的:(GIF图片的问题汇总(类型判断、压缩、保存到相册))