[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6974":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":46,"readmeContent":47,"aiSummary":48,"trendingCount":16,"starSnapshotCount":16,"syncStatus":18,"lastSyncTime":49,"discoverSource":50},6974,"HXPhotoPicker","SilenceLove\u002FHXPhotoPicker","SilenceLove","图片\u002F视频选择器 - 支持LivePhoto、GIF图片选择、3DTouch预览、在线下载iCloud上的资源、编辑图片\u002F视频、浏览网络图片 功能    Imitation wx photo\u002Fimage picker - support for LivePhoto, GIF image selection, 3DTouch preview, Download the resources on iCloud online, browse the web image function","https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker",null,"Swift",3401,736,49,43,0,1,2,13,3,30.6,"MIT License",false,"master",true,[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"3d-touch","browser","editor","gif","icloud","image","imagepicker","ios","livephoto","photo","photoeditor","photokit","photopicker","phpicker","picker","previewimage","swift","uiimagepickercontroller","videoeditor","2026-06-12 02:01:32","\u003Ch4 align=\"right\">中文 | \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FREADME_EN.md\">English\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fh4>\n      \n\u003Cp align=\"center\">\n    \u003Ca>\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002Fsample_graph.png?raw=true\"  width = \"384\" height = \"292.65\" >\u003C\u002Fa>\n\u003C\u002Fp>\n\u003Cp align=\"center\">\n    \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\">\u003Cimg src=\"https:\u002F\u002Ftravis-ci.org\u002FSilenceLove\u002FHXPhotoPicker.svg?branch=master\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\">\u003Cimg src=\"https:\u002F\u002Fbadgen.net\u002Fbadge\u002Ficon\u002FiOS%2010.0%2B?color=cyan&icon=apple&label\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\">\u003Cimg src=\"http:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fv\u002FHXPhotoPicker.svg?logo=cocoapods&logoColor=ffffff\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fdeveloper.apple.com\u002FSwift\">\u003Cimg src=\"http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flanguage-Swift-orange.svg?logo=common-workflow-language\">\u003C\u002Fa>\n    \u003Ca href=\"http:\u002F\u002Fmit-license.org\">\u003Cimg src=\"http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-333333.svg?logo=letterboxd&logoColor=ffffff\">\u003C\u002Fa>\n    \u003Cdiv align=\"center\">一款图片\u002F视频选择器-支持LivePhoto、GIF选择、iCloud\u002F网络资源在线下载、图片\u002F视频编辑\u003C\u002Fdiv>\n\u003C\u002Fp>\n\n## 目录\n* [功能](#功能)\n* [要求](#要求)\n* [安装](#安装)\n* [示例](#示例)\n    * [快速使用](#示例)\n    * [如何支持GIF\u002F网络图片](#如何支持GIF\u002F网络图片)\n    * [如何获取](#如何获取)\n* [更新记录](#更新记录)\n* [演示效果](#演示效果)\n* [界面展示](#界面展示)\n* [支持❤️](#支持❤️) \n\n## \u003Ca id=\"功能\">\u003C\u002Fa> 功能\n\n- [x] UI 外观支持浅色\u002F深色\u002F自动\u002F自定义\n- [x] 支持多选\u002F混合内容选择\n- [x] 支持的媒体类型：\n    - [x] Photo\n    - [x] GIF\n    - [x] Live Photo\n    - [x] Video\n- [x] 支持的本地资源类型：\n    - [x] Photo\n    - [x] Video\n    - [x] GIF\n    - [x] Live Photo\n- [x] 支持的网络资源类型：\n    - [x] Photo\n    - [x] Video\n- [x] 支持下载iCloud上的资源\n- [x] 支持手势返回\n- [x] 支持滑动选择\n- [x] 编辑图片（支持动图、网络资源）\n    - [x] 涂鸦\n    - [x] 贴纸\n    - [x] 文字\n    - [x] 裁剪\n    - [x] 旋转任意角度\n    - [x] 自定义蒙版\n    - [x] 马赛克\n    - [x] 画面调整\n    - [x] 滤镜\n- [x] 编辑视频（支持网络资源）\n    - [x] 涂鸦\n    - [x] 贴纸（支持GIF）\n    - [x] 文字\n    - [x] 配乐（支持歌词字幕）\n    - [x] 裁剪时长\n    - [x] 裁剪尺寸\n    - [x] 旋转任意角度\n    - [x] 自定义蒙版\n    - [x] 画面调整\n    - [x] 滤镜\n- [x] 相册展现方式\n    - [x] 单独列表\n    - [x] 弹窗\n- [x] 多平台支持\n    - [x] iOS\n    - [x] iPadOS\n    - [x] Mac Catalyst\n- [x] 国际化支持\n    - [x] 🇨🇳 简体中文 (zh-Hans)\n    - [x] 🇨🇳 繁体中文 (zh-Hant)\n    - [x] 🇬🇧 英文 (en)\n    - [x] 🇯🇵 日语 (ja)\n    - [x] 🇰🇷 韩语 (ko)\n    - [x] 🇹🇭 泰语 (th)\n    - [x] 🇮🇳 印尼语 (id)\n    - [x] 🇻🇳 越南语 (vi)\n    - [x] 🇷🇺 俄罗斯 (ru)\n    - [x] 🇩🇪 德国 (de)\n    - [x] 🇫🇷 法国 (fr)\n    - [x] 🇸🇦 阿拉伯 (ar)\n    - [x] ✍️ 自定义语言 (custom)\n    - [ ] 🤝 更多支持... (欢迎PR)\n\n## \u003Ca id=\"要求\">\u003C\u002Fa> 要求\n\n- iOS 10.0+\n- Xcode 12.5+\n- Swift 5.4+\n\n## \u003Ca id=\"安装\">\u003C\u002Fa> 安装\n\n### [Swift Package Manager](https:\u002F\u002Fswift.org\u002Fpackage-manager\u002F)\n\n⚠️ 需要 Xcode 13.0 及以上版本来支持资源文件\u002F本地化文件的添加。\n\n```swift\ndependencies: [\n    .package(url: \"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker.git\", .upToNextMajor(from: \"5.0.5\"))\n]\n```\n\n### [CocoaPods](https:\u002F\u002Fguides.cocoapods.org\u002Fusing\u002Fusing-cocoapods.html)\n\n将下面内容添加到 `Podfile`，并执行依赖更新。\n\n```swift\n\n\u002F\u002F\u002F iOS 10.0+ 默认不支持GIF和网络图片\npod 'HXPhotoPicker'\n\n\u002F\u002F\u002F 使用`SwiftyGif`加载GIF图片\npod 'HXPhotoPicker\u002FSwiftyGif'\n\n\u002F\u002F\u002F 使用`SDWebImage`加载GIF\u002F网络图片\npod 'HXPhotoPicker\u002FSDWebImage'\n\n\u002F\u002F\u002F 使用`Kingfisher v6.0.0`加载GIF\u002F网络图片\npod 'HXPhotoPicker\u002FKingfisher'\n\n\u002F\u002F\u002F 相机不包含定位功能\npod `HXPhotoPicker\u002FNoLocation`\n\n\u002F\u002F\u002F 只有选择器\npod `HXPhotoPicker\u002FPicker`\n\n\u002F\u002F\u002F 只有编辑器\npod `HXPhotoPicker\u002FEditor`\n\n\u002F\u002F\u002F 只有相机\npod `HXPhotoPicker\u002FCamera`\n\u002F\u002F\u002F 不包含定位功能\npod `HXPhotoPicker\u002FCamera\u002FLite`\n\nv4.0以下的ObjC版本\npod 'HXPhotoPickerObjC'\n```\n\n### 准备工作\n\n按需在你的 Info.plist 中添加以下键值:\n\n| Key | 模块 | 备注 |\n| ----- | ----  | ---- |\n| NSPhotoLibraryUsageDescription | Picker | 允许访问相册 |\n| NSPhotoLibraryAddUsageDescription | Picker | 允许保存图片至相册 |\n| PHPhotoLibraryPreventAutomaticLimitedAccessAlert | Picker | 设置为 `YES` iOS 14+ 以禁用自动弹出添加更多照片的弹框(Picker 已适配 Limited 功能，可由用户主动触发，提升用户体验) |\n| NSCameraUsageDescription | Camera | 允许使用相机 |\n| NSMicrophoneUsageDescription | Camera | 允许使用麦克风 |\n\n### \u003Ca id=\"示例\">\u003C\u002Fa> 快速上手\n```swift\nimport HXPhotoPicker\n\nclass ViewController: UIViewController {\n\n    func presentPickerController() {\n        \u002F\u002F 设置与微信主题一致的配置\n        let config = PickerConfiguration.default\n        \n        \u002F\u002F 方法一：async\u002Fawait\n        \u002F\u002F 使用`Photo`\n        let images: [UIImage] = try await Photo.picker(config)\n        let urls: [URL] = try await Photo.picker(config)\n        let urlResult: [AssetURLResult] = try await Photo.picker(config)\n        let assetResult: [AssetResult] = try await Photo.picker(config)\n        \u002F\u002F 使用`PhotoPickerController`\n        let images: [UIImage] = try await PhotoPickerController.picker(config)\n        let urls: [URL] = try await PhotoPickerController.picker(config)\n        let urlResult: [AssetURLResult] = try await PhotoPickerController.picker(config)\n        let assetResult: [AssetResult] = try await PhotoPickerController.picker(config)\n        \n        let pickerResult = try await Photo.picker(config)\n        let images: [UIImage] = try await pickerResult.objects()\n        let urls: [URL] = try await pickerResult.objects()\n        let urlResults: [AssetURLResult] = try await pickerResult.objects()\n        let assetResults: [AssetResult] = try await pickerResult.objects()\n        \n        \u002F\u002F 方法二：\n        let pickerController = PhotoPickerController(picker: config)\n        pickerController.pickerDelegate = self\n        \u002F\u002F 当前被选择的资源对应的 PhotoAsset 对象数组\n        pickerController.selectedAssetArray = selectedAssets \n        \u002F\u002F 是否选中原图\n        pickerController.isOriginal = isOriginal\n        present(pickerController, animated: true, completion: nil)\n        \n        \u002F\u002F 方法三：\n        Photo.picker(\n            config\n        ) { result, pickerController in\n            \u002F\u002F 选择完成的回调\n            \u002F\u002F result 选择结果\n            \u002F\u002F  .photoAssets 当前选择的数据\n            \u002F\u002F  .isOriginal 是否选中了原图\n            \u002F\u002F photoPickerController 对应的照片选择控制器\n        } cancel: { pickerController in\n            \u002F\u002F 取消的回调\n            \u002F\u002F photoPickerController 对应的照片选择控制器 \n        }\n    }\n}\n\nextension ViewController: PhotoPickerControllerDelegate {\n    \n    \u002F\u002F\u002F 选择完成之后调用\n    \u002F\u002F\u002F - Parameters:\n    \u002F\u002F\u002F   - pickerController: 对应的 PhotoPickerController\n    \u002F\u002F\u002F   - result: 选择的结果\n    \u002F\u002F\u002F     result.photoAssets  选择的资源数组\n    \u002F\u002F\u002F     result.isOriginal   是否选中原图\n    func pickerController(\n        _ pickerController: PhotoPickerController, \n        didFinishSelection result: PickerResult\n    ) {\n        \u002F\u002F async\u002Fawait\n        let images: [UIImage] = try await result.objects()\n        let urls: [URL] = try await result.objects()\n        let urlResults: [AssetURLResult] = try await result.objects()\n        let assetResults: [AssetResult] = try await result.objects()\n        \n        result.getImage { (image, photoAsset, index) in\n            if let image = image {\n                print(\"success\", image)\n            }else {\n                print(\"failed\")\n            }\n        } completionHandler: { (images) in\n            print(images)\n        }\n    }\n    \n    \u002F\u002F\u002F 点击取消时调用\n    \u002F\u002F\u002F - Parameter pickerController: 对应的 PhotoPickerController\n    func pickerController(didCancel pickerController: PhotoPickerController) {\n        \n    }\n}\n```\n\n### \u003Ca id=\"如何支持GIF\u002F网络图片\">\u003C\u002Fa> 如何支持GIF\u002F网络图片 [HXImageViewProtocol](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Ftree\u002Fmaster\u002FSources\u002FHXPhotoPicker\u002FCore\u002FConfig\u002FHXImageViewProtocol.swift)\n\n\u003Cdetails>\n  \u003Csummary>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Ftree\u002Fmaster\u002FSources\u002FImageView\u002FGIFImageView.swift\">SwiftyGif\u003C\u002Fa> \u003C\u002Fstrong>\u003C\u002Fsummary>\n  \n```swift\nPickerConfiguration.imageViewProtocol = GIFImageView.self\n\npublic class GIFImageView: UIImageView, HXImageViewProtocol {\n    public func setImageData(_ imageData: Data?) {\n        guard let imageData else {\n            clear()\n            SwiftyGifManager.defaultManager.deleteImageView(self)\n            image = nil\n            return\n        }\n        if let image = try? UIImage(gifData: imageData) {\n            setGifImage(image)\n        }else {\n            image = .init(data: imageData)\n        }\n    }\n    \n    public func _startAnimating() {\n        startAnimatingGif()\n    }\n    \n    public func _stopAnimating() {\n        stopAnimatingGif()\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Ftree\u002Fmaster\u002FSources\u002FImageView\u002FSDImageView.swift\">SDWebImage\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fsummary>\n  \n```swift\nPickerConfiguration.imageViewProtocol = SDImageView.self\n\npublic class SDImageView: SDAnimatedImageView, HXImageViewProtocol {\n    public func setImageData(_ imageData: Data?) {\n        guard let imageData else { return }\n        let image = SDAnimatedImage(data: imageData)\n        self.image = image\n    }\n    \n    @discardableResult\n    public func setImage(with resource: ImageDownloadResource, placeholder: UIImage?, options: ImageDownloadOptionsInfo?, progressHandler: ((CGFloat) -> Void)?, completionHandler: ((Result\u003CUIImage, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        var sdOptions: SDWebImageOptions = []\n        var context: [SDWebImageContextOption: Any] = [:]\n        if let options {\n            for option in options {\n                switch option {\n                case .imageProcessor(let size):\n                    let imageProcessor = SDImageResizingTransformer(size: size, scaleMode: .aspectFill)\n                    context[.imageTransformer] = imageProcessor\n                case .onlyLoadFirstFrame:\n                    sdOptions.insert(.decodeFirstFrameOnly)\n                case .memoryCacheExpirationExpired:\n                    sdOptions.insert(.refreshCached)\n                case .cacheOriginalImage, .fade, .scaleFactor:\n                    break\n                }\n            }\n        }\n        sd_setImage(with: resource.downloadURL, placeholderImage: placeholder, options: sdOptions, context: context) { receivedSize, totalSize, _ in\n            let progress = CGFloat(receivedSize) \u002F CGFloat(totalSize)\n            DispatchQueue.main.async {\n                progressHandler?(progress)\n            }\n        } completed: { image, error, cacheType, sourceURL in\n            if let image {\n                completionHandler?(.success(image))\n            }else {\n                if let error = error as? NSError, error.code == NSURLErrorCancelled {\n                    completionHandler?(.failure(.cancel))\n                    return\n                }\n                completionHandler?(.failure(.error(error)))\n            }\n        }\n        let downloadTask = ImageDownloadTask { [weak self] in\n            self?.sd_cancelCurrentImageLoad()\n        }\n        return downloadTask\n    }\n    \n    @discardableResult\n    public func setVideoCover(with url: URL, placeholder: UIImage?, completionHandler: ((Result\u003CUIImage, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        let cacheKey = url.absoluteString\n        if SDImageView.isCached(forKey: cacheKey) {\n            SDImageCache.shared.queryImage(forKey: cacheKey, options: [], context: nil) { (image, data, _) in\n                if let image {\n                    completionHandler?(.success(image))\n                }else {\n                    completionHandler?(.failure(.error(nil)))\n                }\n            }\n            return nil\n        }\n        var imageGenerator: AVAssetImageGenerator?\n        let avAsset = PhotoTools.getVideoThumbnailImage(url: url, atTime: 0.1) {\n            imageGenerator = $0\n        } completion: { _, image, _ in\n            guard let image else {\n                completionHandler?(.failure(.error(nil)))\n                return\n            }\n            SDImageCache.shared.store(image, imageData: nil, forKey: cacheKey, cacheType: .all) {\n                DispatchQueue.main.async {\n                    completionHandler?(.success(image))\n                }\n            }\n        }\n        let task = ImageDownloadTask {\n            avAsset.cancelLoading()\n            imageGenerator?.cancelAllCGImageGeneration()\n        }\n        return task\n    }\n    \n    @discardableResult\n    public static func download(with resource: ImageDownloadResource, options: ImageDownloadOptionsInfo?, progressHandler: ((CGFloat) -> Void)?, completionHandler: ((Result\u003CImageDownloadResult, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        var sdOptions: SDWebImageDownloaderOptions = []\n        var context: [SDWebImageContextOption: Any] = [:]\n        if let options {\n            for option in options {\n                switch option {\n                case .imageProcessor(let size):\n                    let imageProcessor = SDImageResizingTransformer(size: size, scaleMode: .aspectFill)\n                    context[.imageTransformer] = imageProcessor\n                case .onlyLoadFirstFrame:\n                    sdOptions.insert(.decodeFirstFrameOnly)\n                default:\n                    break\n                }\n            }\n        }\n        let key = resource.cacheKey\n        if SDImageView.isCached(forKey: key) {\n            SDImageCache.shared.queryImage(forKey: key, options: [], context: nil) { (image, data, _) in\n                if let data = data  {\n                    completionHandler?(.success(.init(imageData: data)))\n                } else if let image = image as? SDAnimatedImage, let data = image.animatedImageData {\n                    completionHandler?(.success(.init(imageData: data)))\n                } else if let image {\n                    completionHandler?(.success(.init(image: image)))\n                } else {\n                    completionHandler?(.failure(.error(nil)))\n                }\n            }\n            return nil\n        }\n        let operation = SDWebImageDownloader.shared.downloadImage(\n            with: resource.downloadURL,\n            options: sdOptions,\n            context: context,\n            progress: { receivedSize, totalSize, _ in\n                let progress = CGFloat(receivedSize) \u002F CGFloat(totalSize)\n                DispatchQueue.main.async {\n                    progressHandler?(progress)\n                }\n            },\n            completed: { image, data, error, finished in\n                guard let data = data, finished, error == nil else {\n                    completionHandler?(.failure(.error(error)))\n                    return\n                }\n                DispatchQueue.global().async {\n                    let format = NSData.sd_imageFormat(forImageData: data)\n                    if format == SDImageFormat.GIF, let gifImage = SDAnimatedImage(data: data) {\n                        SDImageCache.shared.store(gifImage, imageData: data, forKey: key, options: [], context: nil, cacheType: .all) {\n                            DispatchQueue.main.async {\n                                completionHandler?(.success(.init(imageData: data)))\n                            }\n                        }\n                        return\n                    }\n                    if let image = image {\n                        SDImageCache.shared.store(image, imageData: data, forKey: key, options: [], context: nil, cacheType: .all) {\n                            DispatchQueue.main.async {\n                                completionHandler?(.success(.init(image: image)))\n                            }\n                        }\n                    }\n                }\n            }\n        )\n        let downloadTask = ImageDownloadTask {\n            operation?.cancel()\n        }\n        return downloadTask\n    }\n    \n    public func _startAnimating() {\n        startAnimating()\n    }\n    \n    public func _stopAnimating() {\n        stopAnimating()\n    }\n    \n    public static func getCacheKey(forURL url: URL) -> String {\n        SDWebImageManager.shared.cacheKey(for: url) ?? \"\"\n    }\n    \n    public static func getCachePath(forKey key: String) -> String {\n        SDImageCache.shared.cachePath(forKey: key) ?? \"\"\n    }\n    \n    public static func isCached(forKey key: String) -> Bool {\n        FileManager.default.fileExists(atPath: getCachePath(forKey: key))\n    }\n    \n    public static func getInMemoryCacheImage(forKey key: String) -> UIImage? {\n        SDImageCache.shared.imageFromMemoryCache(forKey: key)\n    }\n    \n    public static func getCacheImage(forKey key: String, completionHandler: ((UIImage?) -> Void)?) {\n        SDImageCache.shared.queryImage(forKey: key, context: nil, cacheType: .all) { image, data, _ in\n            if let data, let image = SDAnimatedImage(data: data) {\n                completionHandler?(image)\n            }else if let image {\n                completionHandler?(image)\n            }else {\n                completionHandler?(nil)\n            }\n        }\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Ftree\u002Fmaster\u002FSources\u002FImageView\u002FKFImageView.swift\">Kingfisher(v6.0.0)\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fsummary>\n  \n```swift\nPickerConfiguration.imageViewProtocol = KFImageView.self\n\npublic class KFImageView: AnimatedImageView, HXImageViewProtocol {\n    public func setImageData(_ imageData: Data?) {\n        guard let imageData else { return }\n        let image: KFCrossPlatformImage? = DefaultImageProcessor.default.process(item: .data(imageData), options: .init([]))\n        self.image = image\n    }\n    \n    @discardableResult\n    public func setImage(with resource: ImageDownloadResource, placeholder: UIImage?, options: ImageDownloadOptionsInfo?, progressHandler: ((CGFloat) -> Void)?, completionHandler: ((Result\u003CUIImage, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        var kfOptions: KingfisherOptionsInfo = []\n        if let options {\n            for option in options {\n                switch option {\n                case .fade(let duration):\n                    kfOptions += [.transition(.fade(duration))]\n                case .imageProcessor(let size):\n                    let imageProcessor = DownsamplingImageProcessor(size: size)\n                    kfOptions += [.processor(imageProcessor)]\n                case .onlyLoadFirstFrame:\n                    kfOptions += [.onlyLoadFirstFrame]\n                case .cacheOriginalImage:\n                    kfOptions += [.cacheOriginalImage]\n                case .memoryCacheExpirationExpired:\n                    kfOptions += [.memoryCacheExpiration(.expired)]\n                case .scaleFactor(let scale):\n                    kfOptions += [.scaleFactor(scale)]\n                }\n            }\n        }\n        let imageResource = Kingfisher.ImageResource(downloadURL: resource.downloadURL, cacheKey: resource.cacheKey)\n        if let indicatorColor = resource.indicatorColor {\n            kf.indicatorType = .activity\n            (kf.indicator?.view as? UIActivityIndicatorView)?.color = indicatorColor\n        }\n        let task = kf.setImage(with: imageResource, placeholder: placeholder, options: kfOptions) { receivedSize, totalSize in\n            progressHandler?(CGFloat(receivedSize) \u002F CGFloat(totalSize))\n        } completionHandler: {\n            switch $0 {\n            case .success(let result):\n                completionHandler?(.success(result.image))\n            case .failure(let error):\n                completionHandler?(.failure(error.isTaskCancelled ? .cancel : .error(error)))\n            }\n        }\n        let downloadTask = ImageDownloadTask {\n            task?.cancel()\n        }\n        return downloadTask\n    }\n    \n    public func setVideoCover(with url: URL, placeholder: UIImage?, completionHandler: ((Result\u003CUIImage, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        let provider = AVAssetImageDataProvider(assetURL: url, seconds: 0.1)\n        provider.assetImageGenerator.appliesPreferredTrackTransform = true\n        let task = KF.dataProvider(provider)\n            .placeholder(placeholder)\n            .onSuccess { result in\n                completionHandler?(.success(result.image))\n            }\n            .onFailure { error in\n                completionHandler?(.failure(error.isTaskCancelled ? .cancel : .error(error)))\n            }\n            .set(to: self)\n        let downloadTask = ImageDownloadTask {\n            task?.cancel()\n        }\n        return downloadTask\n    }\n    \n    @discardableResult\n    public static func download(with resource: ImageDownloadResource, options: ImageDownloadOptionsInfo?, progressHandler: ((CGFloat) -> Void)?, completionHandler: ((Result\u003CImageDownloadResult, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {\n        let key = resource.cacheKey\n        var kfOptions: KingfisherOptionsInfo = []\n        if let options {\n            for option in options {\n                switch option {\n                case .fade(let duration):\n                    kfOptions += [.transition(.fade(duration))]\n                case .imageProcessor(let size):\n                    let imageProcessor = DownsamplingImageProcessor(size: size)\n                    kfOptions += [.processor(imageProcessor)]\n                case .onlyLoadFirstFrame:\n                    kfOptions += [.onlyLoadFirstFrame]\n                case .cacheOriginalImage:\n                    kfOptions += [.cacheOriginalImage]\n                case .memoryCacheExpirationExpired:\n                    kfOptions += [.memoryCacheExpiration(.expired)]\n                case .scaleFactor(let scale):\n                    kfOptions += [.scaleFactor(scale)]\n                }\n            }\n        }\n        if ImageCache.default.isCached(forKey: key) {\n            ImageCache.default.retrieveImage(\n                forKey: key,\n                options: kfOptions\n            ) { (result) in\n                switch result {\n                case .success(let value):\n                    if let data = value.image?.kf.gifRepresentation() {\n                        completionHandler?(.success(.init(imageData: data)))\n                    }else if let image = value.image {\n                        completionHandler?(.success(.init(image: image)))\n                    }else {\n                        completionHandler?(.failure(.error(nil)))\n                    }\n                case .failure(let error):\n                    completionHandler?(.failure(.error(error)))\n                }\n            }\n            return nil\n        }\n        let task =  ImageDownloader.default.downloadImage(with: resource.downloadURL, options: kfOptions) { receivedSize, totalSize in\n            let progress = CGFloat(receivedSize) \u002F CGFloat(totalSize)\n            progressHandler?(progress)\n        } completionHandler: {\n            switch $0 {\n            case .success(let value):\n                DispatchQueue.global().async {\n                    if let gifImage = DefaultImageProcessor.default.process(\n                        item: .data(value.originalData),\n                        options: .init([])\n                    ) {\n                        ImageCache.default.store(\n                            gifImage,\n                            original: value.originalData,\n                            forKey: key\n                        )\n                        DispatchQueue.main.async {\n                            completionHandler?(.success(.init( imageData: value.originalData)))\n                        }\n                        return\n                    }\n                    ImageCache.default.store(\n                        value.image,\n                        original: value.originalData,\n                        forKey: key\n                    )\n                    DispatchQueue.main.async {\n                        completionHandler?(.success(.init(image: value.image)))\n                    }\n                }\n            case .failure(let error):\n                completionHandler?(.failure(.error(error)))\n            }\n        }\n        let downloadTask = ImageDownloadTask {\n            task?.cancel()\n        }\n        return downloadTask\n    }\n    \n    public func _startAnimating() {\n        startAnimating()\n    }\n    \n    public func _stopAnimating() {\n        stopAnimating()\n    }\n    \n    public static func getCacheKey(forURL url: URL) -> String {\n        url.cacheKey\n    }\n    \n    public static func getCachePath(forKey key: String) -> String {\n        ImageCache.default.cachePath(forKey: key)\n    }\n    \n    public static func isCached(forKey key: String) -> Bool {\n        ImageCache.default.isCached(forKey: key)\n    }\n    \n    public static func getInMemoryCacheImage(forKey key: String) -> UIImage? {\n        ImageCache.default.retrieveImageInMemoryCache(forKey: key)\n    }\n    \n    public static func getCacheImage(forKey key: String, completionHandler: ((UIImage?) -> Void)?) {\n        ImageCache.default.retrieveImage(forKey: key, options: []) {\n            switch $0 {\n            case .success(let result):\n                completionHandler?(result.image)\n            case .failure:\n                completionHandler?(nil)\n            }\n        }\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\n### \u003Ca id=\"如何获取\">\u003C\u002Fa> 如何获取\n\n#### 获取 UIImage\n\n```swift\n\u002F\u002F\u002F 如果为视频的话获取则是视频封面\n\u002F\u002F async\u002Fawait\n\u002F\u002F compression: 压缩参数，不传则不压缩 \nlet image: UIImage = try await photoAsset.object(compression)\n\n\u002F\u002F\u002F 获取指定`Size`的`UIImage`\n\u002F\u002F\u002F targetSize: 指定imageSize\n\u002F\u002F\u002F targetMode: 裁剪模式\nlet image = try await photoAsset.image(targetSize: .init(width: 200, height: 200), targetMode: .fill)\n\n\u002F\u002F compressionQuality: 压缩参数，不传则不压缩 \nphotoAsset.getImage(compressionQuality: compressionQuality) { image in\n    print(image)\n}\n```\n\n#### 获取 URL\n\n```swift\n\u002F\u002F async\u002Fawait \n\u002F\u002F compression: 压缩参数，不传则不压缩 \nlet url: URL = try await photoAsset.object(compression)\nlet urlResult: AssetURLResult = try await photoAsset.object(compression)\n\n\u002F\u002F compression: 压缩参数，不传则不压缩\nphotoAsset.getURL(compression: compression) { result in\n    switch result {\n    case .success(let urlResult):\n        \u002F\u002F 媒体类型\n        switch urlResult.mediaType {\n        case .photo:\n            \u002F\u002F 图片\n        case .video:\n            \u002F\u002F 视频\n        }\n        \n        \u002F\u002F url类型\n        switch urlResult.urlType {\n        case .local:\n            \u002F\u002F 本地URL\n        case .network:\n            \u002F\u002F 网络URL\n        }\n        \n        \u002F\u002F 获取的地址\n        print(urlResult.url)\n        \n        \u002F\u002F LivePhoto 里面包含的 图片和视频 url\n        print(urlResult.livePhoto) \n        \n    case .failure(let error):\n        print(error)\n    }\n}\n```\n\n#### 获取其他\n\n```swift\n\u002F\u002F\u002F 获取缩略图\nlet thumImage = try await photoAsset.requesThumbnailImage()\n\n\u002F\u002F\u002F 获取预览图\nlet previewImage = try await photoAsset.requestPreviewImage()\n\n\u002F\u002F\u002F 获取 AVAsset\nlet avAsset = try await photoAsset.requestAVAsset()\n\n\u002F\u002F\u002F 获取 AVPlayerItem\nlet playerItem = try await photoAsset.requestPlayerItem()\n\n\u002F\u002F\u002F 获取 PHLivePhoto\nlet livePhoto = try await photoAsset.requestLivePhoto()\n```\n\n## \u003Ca id=\"更新记录\">\u003C\u002Fa> 更新日志\n\n\u003Cdetails open id=\"最近更新\">\n  \u003Csummary>\u003Cstrong>最近更新\u003C\u002Fstrong>\u003C\u002Fsummary>\n  \n| 版本 | 发布时间 | Xcode | Swift | iOS |\n| ---- | ----  | ---- | ---- | ---- |\n| [v5.0.5](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#505) | 2025-12-01 | 26.0.0 | 6.0.0 | 10.0+ | \n\n\u003C\u002Fdetails>\n\n\u003Cdetails id=\"历史记录\">\n  \u003Csummary>\u003Cstrong>历史记录\u003C\u002Fstrong>\u003C\u002Fsummary>\n  \n| 版本 | 发布时间 | Xcode | Swift | iOS |\n| ---- | ----  | ---- | ---- | ---- |\n| [v5.0.4](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#504) | 2025-09-19 | 26.0.0 | 6.0.0 | 10.0+ | \n| [v5.0.3](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#503) | 2025-07-03 | 16.2.0 | 6.0.0 | 10.0+ | \n| [v5.0.2](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#502) | 2025-05-21 | 16.2.0 | 6.0.0 | 10.0+ | \n| [v5.0.1](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#501) | 2025-03-31 | 16.0.0 | 6.0.0 | 10.0+ | \n| [v5.0.0](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#500) | 2025-03-03 | 16.0.0 | 6.0.0 | 10.0+ | \n| [v4.2.5](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#425) | 2025-02-12 | 16.0.0 | 6.0.0 | 13.0+ | \n| [v4.2.4](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#424) | 2024-12-14 | 16.0.0 | 6.0.0 | 13.0+ | \n| [v4.2.3](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#423) | 2024-08-05 | 16.0.0 | 6.0.0 | 12.0+ | \n| [v4.2.2](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#422) | 2024-07-08 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.2.1](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#421) | 2024-05-18 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.2.0](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#420) | 2024-04-23 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.9](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#419) | 2024-04-09 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.8](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#418) | 2024-03-24 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.7](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#417) | 2024-03-09 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.6](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#416) | 2024-02-16 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.5](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#415) | 2024-01-10 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.4](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#414) | 2023-12-24 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.3](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#413) | 2023-12-16 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.2](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#412) | 2023-12-02 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.1](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#411) | 2023-11-14 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.1.0](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#410) | 2023-11-07 | 15.0.0 | 5.9.0 | 12.0+ | \n| [v4.0.9](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#409) | 2023-10-22 | 15.0.0 | 5.9.0 | 12.0+ |\n| [v4.0.8](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#408) | 2023-10-13 | 15.0.0 | 5.9.0 | 12.0+ |\n| [v4.0.7](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#407) | 2023-09-23 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.6](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#406) | 2023-09-09 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.5](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#405) | 2023-08-12 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.4](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#404) | 2023-07-30 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.3](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#403) | 2023-07-06 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.2](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#402) | 2023-06-24 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.1](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#401) | 2023-06-17 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v4.0.0](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPicker\u002Fblob\u002Fmaster\u002FDocumentation\u002FRELEASE_NOTE_CN.md#400) | 2023-06-15 | 14.3.0 | 5.7.0 | 12.0+ |\n| [v3.0.0](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FHXPhotoPickerObjC#-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95---update-history) | 2022-09-18 | 14.0.0 | ----- | 8.0+ | \n\n\u003C\u002Fdetails>\n\n## \u003Ca id=\"演示效果\">\u003C\u002Fa> 演示效果\n\n| 选择照片 | 图片编辑 | 视频编辑 | \n| ---- | ----  | ---- |\n| [![IMAGE ALT TEXT](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FVideos\u002Fphoto_list_picker_cover.png?raw=true)](http:\u002F\u002Foss-cn-hangzhou.aliyuncs.com\u002Ftsnrhapp\u002Fshop\u002Fvideos\u002F83862ab94facfd8979eb6148094908b2.mp4) | [![IMAGE ALT TEXT](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FVideos\u002Fphoto_editor_cover.png?raw=true)](http:\u002F\u002Foss-cn-hangzhou.aliyuncs.com\u002Ftsnrhapp\u002Fshop\u002Fvideos\u002F3c81199474e33006e2cebd5f6241ead5.mp4) | [![IMAGE ALT TEXT](https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FVideos\u002Fvideo_editor_cover.png?raw=true)](http:\u002F\u002Foss-cn-hangzhou.aliyuncs.com\u002Ftsnrhapp\u002Fshop\u002Fvideos\u002F8c1cf86f32329e6464d327781f15041a.mp4) | \n\n## \u003Ca id=\"界面展示\">\u003C\u002Fa> 界面展示\n\n| \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_photo_picker_list.png?raw=true\"> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_photo_preview.png?raw=true\"> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_photo_editor_filter.png?raw=true\"> | \n| ---- | ----  | ---- |\n| \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_video_editor_time.png?raw=true\"> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_video_editor_edit.png?raw=true\"> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_video_editor_crop_size.png?raw=true\"> |\n\n| \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_photo_editor_crop_size_horizontal_screen.png?raw=true\"> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FREADME\u002FPhotos\u002Fsample_graph_video_editor_crop_size_horizontal_screen.png?raw=true\"> |\n| ---- | ----  |\n\n## 版权协议 \nHXPhotoPicker 基于 MIT 协议进行分发和使用，更多信息参见[协议文件](.\u002FLICENSE)。 \n\n## \u003Ca id=\"支持❤️\">\u003C\u002Fa> 支持❤️\n* [**★ Star**](#)\n* 支持作者☕️ \n    \n\u003Cdiv align=\"left\">\u003Ca href=\"https:\u002F\u002Fwww.buymeacoffee.com\u002Ffengye\" target=\"_blank\">\u003Cimg src=\"https:\u002F\u002Fcdn.buymeacoffee.com\u002Fbuttons\u002Fv2\u002Fdefault-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" >\u003C\u002Fa>\u003C\u002Fdiv> \n\n| \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FSupport\u002Fbmc_qr.png?raw=true\" width = \"135\" height = \"135\" \u002F> | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FSupport\u002Fap.jpeg?raw=true\" width = \"100\" height = \"135.75\" \u002F>   | \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FSilenceLove\u002FPictureMaterial\u002Fblob\u002Fmain\u002FHXPhotoPicker\u002FSupport\u002Fwp.jpeg?raw=true\" width = \"100\" height = \"135.75\" \u002F> |\n| ------ | ------ | ------ | \n\n[![Stargazers over time](https:\u002F\u002Fstarchart.cc\u002FSilenceLove\u002FHXPhotoPicker.svg)](https:\u002F\u002Fstarchart.cc\u002FSilenceLove\u002FHXPhotoPicker)\n\n\n[🔝回到顶部](#readme)\n","HXPhotoPicker 是一个用于 iOS 的图片和视频选择器，支持 LivePhoto、GIF 选择、iCloud\u002F网络资源在线下载以及图片和视频编辑。其核心功能包括多选\u002F混合内容选择、多种媒体类型（如照片、GIF、Live Photo 和视频）的支持，以及丰富的编辑选项，例如涂鸦、贴纸、文字、裁剪、旋转、滤镜等。此外，它还具备 3D Touch 预览、手势返回、滑动选择等功能，并且支持浅色\u002F深色模式切换及自定义主题。HXPhotoPicker 适用于需要用户从本地或网络选取并编辑多媒体内容的应用场景，如社交应用、内容创作工具等。该项目采用 Swift 编写，兼容 iOS 10.0 及以上版本，并通过 CocoaPods 或 Swift Package Manager 方式进行集成。","2026-06-11 03:09:56","top_language"]