尝试将 [UIImage] 合并到单个 GIF 图像时出现内存泄漏问题

问题描述 投票:0回答:1

我正在尝试将多个 UIImage 组合为 1 个 gif 动画图像。如果帧数 (UIImages) 超过 20,我会遇到问题。应用程序由于内存泄漏而关闭。当

createGIF
开始制作gif时,内存从200MB跳到2GB,并不断增加,直到应用程序因内存泄漏而崩溃。

这是我的代码:

func createGIF(from images: [UIImage], loopCount: Int = 0, frameDuration: TimeInterval = 0.1, completion: @escaping (URL?) -> Void) {
    guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        print("Error: Unable to create documentsDirectory.")
        completion(nil)
        return
    }

    let gifURL = documentsDirectory.appendingPathComponent("\(UUID().uuidString).gif")

    guard let destination = CGImageDestinationCreateWithURL(gifURL as CFURL, kUTTypeGIF, images.count, nil) else {
        print("Error: Unable to create CGImageDestination.")
        completion(nil)
        return
    }

    let gifProperties = [
        kCGImagePropertyGIFDictionary as String: [
                    kCGImagePropertyGIFLoopCount as String: loopCount
                ]
    ]
    CGImageDestinationSetProperties(destination, gifProperties as CFDictionary)

    // Process frames in batches to reduce memory usage
    let batchSize = 10
    let totalFrames = images.count

    for startIndex in stride(from: 0, to: totalFrames, by: batchSize) {
        let endIndex = min(startIndex + batchSize, totalFrames)
        let batchImages = Array(images[startIndex..<endIndex])

        for image in batchImages {
            if let cgImage = image.cgImage {
                let frameProperties = [
                    kCGImagePropertyGIFDictionary as String: [
                        kCGImagePropertyGIFDelayTime as String: frameDuration
                    ]
                ]
                CGImageDestinationAddImage(destination, cgImage, frameProperties as CFDictionary)
            } else {
                print("Error: Unable to retrieve CGImage from UIImage.")
                completion(nil)
                return
            }
        }
    }

    guard CGImageDestinationFinalize(destination) else {
        print("Error: Failed to finalize CGImageDestination.")
        completion(nil)
        return
    }

    completion(gifURL)
}

我正在尝试从 UIImage 数组实现贴纸动画 gif。 我在这里忘记了什么或者当我使用超过 20 FPS 时导致内存增加到超过 2GB 的问题是什么。

swift uiimage gif
1个回答
0
投票

好吧,在生成实际的 gif 图像之前使用

DispatchGroup
并调整图像大小并将它们转换为 CGImage 解决了我的问题,生成 gif 时内存最大在 150 到 200mb 之间。

这是最终的代码可以帮助某人:

public func generateGifFromImages(images: [UIImage], colorSpace: colorSpace, delayTime: Double, loopCount: Int,completion: @escaping (URL?) -> Void) {
        
        // create empty file to hold gif
        let destinationFilename = String(NSUUID().uuidString + ".gif")
        let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(destinationFilename)

        let gifGroup = DispatchGroup()
        var tempImages: [UIImage] = []
        for image in images {
            gifGroup.enter()
            tempImages.append(image.resized(to: CGSize(width: 512,height: 512)))
            gifGroup.leave()
        }
        
        gifGroup.notify(queue: .main) {
            let gifFileProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: loopCount]]  as CFDictionary
            let gifFrameProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: delayTime]] as CFDictionary
            if let url = fileURL as CFURL? {
                if let destination = CGImageDestinationCreateWithURL(url, UTType.gif.identifier as CFString, images.count, nil) {
                    CGImageDestinationSetProperties(destination, gifFileProperties)
                    for image in tempImages {
                        if let cgImage = image.cgImage {
                            CGImageDestinationAddImage(destination, cgImage, gifFrameProperties)
                        }
                    }
                    if !CGImageDestinationFinalize(destination) {
                        print("Failed to finalize the image destination")
                    }else{
                        completion(fileURL)
                    }
                }
            }
        }
    }

这是调整大小扩展:

extension UIImage {
  /**
    Resizes the image.

    - Parameters:
      - scale: If this is 1, `newSize` is the size in pixels.
  */
  @nonobjc public func resized(to newSize: CGSize, scale: CGFloat = 1) -> UIImage {
    let format = UIGraphicsImageRendererFormat.default()
    format.scale = scale
    let renderer = UIGraphicsImageRenderer(size: newSize, format: format)
    let image = renderer.image { _ in
      draw(in: CGRect(origin: .zero, size: newSize))
    }
    return image
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.