首页 > 解决方案 > CGImageDestinationAddImage 的意外行为取决于我在 Swift 中的 UIImage var

问题描述

我有一个函数可以生成带有 UIImages 数组的 gif。图像数组大小为 31,但我将容量设置为 15,因为我只使用选择图像。

最终,我遇到的问题是,当我使用函数调整 CGImage 的大小并将其用作 CGImageDestinationAddImage 中的图像时,生成的 gif 是我之前发送的照片,而不是我通过发送的照片这次发挥作用。我不知道这是怎么发生的,因为即使我关闭了应用程序,生成的 gif 仍然可以生成我之前使用的图像数组。

下面是基本的 generateGIF 和 imageWithImage 函数,然后我将展示不同的东西我尝试过得到的结果。

func generateGIF(photos: [UIImage], filename: String) -> Bool {

    let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    let path = documentsDirectoryPath.appending(filename)

    let fileProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]

    var gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.1]] // actual speed is 0.2

    gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImageDestinationLossyCompressionQuality as String: 0.1]]

    let cfURL = URL(fileURLWithPath: path) as CFURL

    let imageCapacity = 15

    if let destination = CGImageDestinationCreateWithURL(cfURL, kUTTypeGIF, imageCapacity, nil) {

        CGImageDestinationSetProperties(destination, fileProperties as CFDictionary?)

        var inc:Int = 0

        for _ in 0..<imageCapacity { // actual photos.count is 31
            // I create 'photo' to determine what new size I should
            // use, for my own convenience, not included in this code
            let photo = photos[inc]

            let width:CGFloat = 200

            let smallerPhoto = imageWithImage(image:photos[inc], newWidth:width)

            CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

            inc += 2
        }

    }
    // do something with gif, i.e. save to photo albums or display
    // in my case I save using path as a URL
}

func imageWithImage(image:UIImage, newWidth:CGFloat) -> UIImage{
    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale
    let newSize = CGSize(width: newWidth, height: newHeight)

    let renderer = UIGraphicsImageRenderer(size: newSize)

    let image = renderer.image { (context) in
        image.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
    }
    return image
}

正如我所解释的,使用上面的代码生成的 gif 将从我之前捕获的图像中生成一个 gif。

如果我在 CGImageDestinationAddImage 中使用“照片”,则生成的 gif 是我所期望的,而不是我上次创建的,但是 CGImage 没有调整大小,因为我没有通过该函数传递它们。

CGImageDestinationAddImage(destination, photo.cgImage!, gifProperties as CFDictionary?)

作为一个实验,我将 smallPhoto 定义为“照片”,期望它复制我之前定义的内容,并将其与 CGImageDestinationAddImage 一起使用。相反,生成的 gif 来自我上次发送给函数 generateGIF 函数的 UIImages 数组。

let smallerPhoto = photo
CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

或者,我尝试将 smallPhoto 直接定义为照片中的当前数组索引,并在 CGImageDestinationAddImage 中使用它。这给了我传递给 generateGIF 的正确图像集。但是,这会跳过调整 CGImages 的大小,这是我需要做的。

let smallerPhoto = photos[inc]
CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

标签: arraysswiftuiimageanimated-gifcgimage

解决方案


我需要使用 CGImageDestinationFinalize(destination) 来完成我的图像。

func generateGIF(照片: [UIImage], 文件名: String) -> Bool {

let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let path = documentsDirectoryPath.appending(filename)

let fileProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]

var gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.1]] // actual speed is 0.2

gifProperties = [kCGImagePropertyGIFDictionary as String: [kCGImageDestinationLossyCompressionQuality as String: 0.1]]

let cfURL = URL(fileURLWithPath: path) as CFURL

let imageCapacity = 15

if let destination = CGImageDestinationCreateWithURL(cfURL, kUTTypeGIF, imageCapacity, nil) {

    CGImageDestinationSetProperties(destination, fileProperties as CFDictionary?)

    var inc:Int = 0

    for _ in 0..<imageCapacity { // actual photos.count is 31
        // I create 'photo' to determine what new size I should
        // use, for my own convenience, not included in this code
        let photo = photos[inc]

        let width:CGFloat = 200

        let smallerPhoto = imageWithImage(image:photos[inc], newWidth:width)

        CGImageDestinationAddImage(destination, smallerPhoto.cgImage!, gifProperties as CFDictionary?)

        inc += 2
    }

}

let finalized:Bool = CGImageDestinationFinalize(destination)

if finalized {
   // do something with gif, i.e. save to photo albums or display
   // in my case I save using path as a URL
}

// return finalized boolean value
return finalized

}


推荐阅读