You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从PHAsset类型的视频资源中提取UIImage格式的预览图

实现方案

你需要使用系统Photos框架提供的PHImageManager即可完成PHAsset到预览UIImage的转换,具体实现如下:

基础通用实现(获取视频默认缩略图)

该方法性能更高,适合列表批量加载视频预览的场景:

import Photos
import UIKit

/// 从视频PHAsset获取预览图
/// - Parameters:
///   - asset: 视频对应的PHAsset资源
///   - targetSize: 期望返回的图片尺寸,传`PHImageManagerMaximumSize`可获取原图尺寸
///   - completion: 结果回调,默认不在主线程,操作UI需自行切到主队列
func getVideoThumbnail(from asset: PHAsset, targetSize: CGSize = CGSize(width: 300, height: 300), completion: @escaping (UIImage?) -> Void) {
    let options = PHImageRequestOptions()
    options.isSynchronous = false
    // 按需调整图片质量策略:.opportunistic先返低清再返高清 / .highQualityFormat仅返高清 / .fastFormat仅返低清
    options.deliveryMode = .highQualityFormat
    // 允许下载iCloud上存储的资源
    options.isNetworkAccessAllowed = true
    
    PHImageManager.default().requestImage(
        for: asset,
        targetSize: targetSize,
        contentMode: .aspectFill,
        options: options
    ) { image, info in
        // 过滤掉自动返回的低清降级图,不需要过滤可以删掉这行判断
        guard let isDegraded = info?[PHImageResultIsDegradedKey] as? Bool, !isDegraded else { return }
        completion(image)
    }
}

自定义时间点预览实现

如果需要获取视频指定秒数位置的预览图,使用AVAssetImageGenerator实现:

import AVFoundation

/// 从视频PHAsset获取指定时间点的预览图
/// - Parameters:
///   - asset: 视频对应的PHAsset资源
///   - seconds: 要截取的视频时间点,单位为秒
///   - completion: 结果回调,默认不在主线程,操作UI需自行切到主队列
func getVideoThumbnailAtTime(from asset: PHAsset, seconds: Double = 1, completion: @escaping (UIImage?) -> Void) {
    let options = PHVideoRequestOptions()
    options.isNetworkAccessAllowed = true
    
    PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, _, _ in
        guard let avAsset = avAsset else {
            completion(nil)
            return
        }
        let imageGenerator = AVAssetImageGenerator(asset: avAsset)
        // 自动修正视频方向
        imageGenerator.appliesPreferredTrackTransform = true
        let targetTime = CMTimeMakeWithSeconds(seconds, preferredTimescale: 600)
        do {
            let cgImage = try imageGenerator.copyCGImage(at: targetTime, actualTime: nil)
            completion(UIImage(cgImage: cgImage))
        } catch {
            completion(nil)
        }
    }
}

注意事项

  • 调用前需要确保已经获取了相册访问权限,否则会返回空图片
  • 所有回调默认在子线程执行,如果要直接更新UI,需要在completion内手动调用DispatchQueue.main.async切换到主线程
  • 批量加载列表预览时建议把deliveryMode设为.fastFormat或者.opportunistic,可以提升滚动流畅度

内容的提问来源于stack exchange,提问作者user15916080

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:09:01