// // ImagePlugin.swift // DLSDK // // Created by osell on 2023/4/14. // import UIKit import Kingfisher import CoreMedia nonisolated(unsafe) let kBrokenNetworkImage = UIImage(named: "Common/image_broken") ?? UIImage() extension UIImage { static var brokenNetworkImage: UIImage { kBrokenNetworkImage } } private let kNetworkImageFailureOptions: KingfisherOptionsInfo = [ .onFailureImage(kBrokenNetworkImage) ] public protocol ImageSource { /// 图片资源URL var imageURL: URL? { get } /// 图片资源字符串 var imageStr: String? { get } } extension ImageSource { var imageURL: URL? { nil } var imageStr: String? { nil } } extension String: ImageSource { public var imageURL: URL? { URL(string: self.urlEncodingWithQueryAllowedCharacters) } public var imageStr: String? { self } } extension URL: ImageSource { public var imageURL: URL? { self } public var imageStr: String? { self.absoluteString.urlDecoded } } // MARK: - UIImageView extension DLWrapper where Base: UIImageView { /// 设置图片 /// - Parameters: /// - url: 图片链接/名称, URL or String /// - placeholder: 可选,默认nil /// - completionHandler: 可选,默认为nil @MainActor public func setImage(with url: ImageSource?, placeholder: UIImage? = nil, completionHandler: ((UIImage?, Error?) -> Void)? = nil) { guard let imageURL = url?.imageURL else { let imageStr = url?.imageStr ?? "" // 如果是本地图片,加载本地图片 if let image = UIImage(named: imageStr) { base.image = image return } // 如果是SDK中图片,则加载SDK中图片 if let image = UIImage(named: imageStr) { base.image = image return } base.image = placeholder ?? .brokenNetworkImage return } // 如果是视频, 获取视频第一帧 if imageURL.imageStr?.contains(".mp4") == true { let source = AVAssetImageDataProvider(assetURL: imageURL, time: CMTimeMakeWithSeconds(0.0, preferredTimescale: 1)) base.kf.setImage( with: source.convertToSource(), placeholder: placeholder, options: kNetworkImageFailureOptions ) { result in switch result { case let .success(imageinfo): completionHandler?(imageinfo.image, nil) case let .failure(error): completionHandler?(nil, error) } } } else { base.kf.setImage( with: imageURL, placeholder: placeholder, options: kNetworkImageFailureOptions ) { result in switch result { case let .success(imageinfo): completionHandler?(imageinfo.image, nil) case let .failure(error): completionHandler?(nil, error) } } } } } // MARK: - Button extension DLWrapper where Base: UIButton { /// 设置按钮图片 /// - Parameters: /// - url: 图片链接, URL or String /// - placeholder: 可选,默认nil /// - completionHandler: 可选,默认为nil @MainActor public func setImage(with url: ImageSource?, for state: UIControl.State, placeholder: UIImage? = nil, completionHandler: ((UIImage?, Error?) -> Void)? = nil) { guard let imageURL = url?.imageURL else { let imageStr = url?.imageStr ?? "" // 如果是本地图片,加载本地图片 if let image = UIImage(named: imageStr) { base.setImage(image, for: state) return } // 如果是SDK中图片,则加载SDK中图片 if let image = UIImage(named: imageStr) { base.setImage(image, for: state) return } // 都不存在,则置为nil base.setImage(placeholder ?? .brokenNetworkImage, for: state) return } base.kf.setImage( with: imageURL, for: state, placeholder: placeholder, options: kNetworkImageFailureOptions, completionHandler: { result in switch result { case let .success(imageinfo): completionHandler?(imageinfo.image, nil) case let .failure(error): completionHandler?(nil, error) } } ) } /// 设置按钮背景图片 /// - Parameters: /// - url: 图片链接, URL or String /// - placeholder: 可选,默认nil /// - completionHandler: 可选,默认为nil @MainActor public func setBackgroundImage(with url: ImageSource?, for state: UIControl.State, placeholder: UIImage? = nil, completionHandler: ((UIImage?, Error?) -> Void)? = nil) { guard let imageURL = url?.imageURL else { let imageStr = url?.imageStr ?? "" // 如果是本地图片,加载本地图片 if let image = UIImage(named: imageStr) { base.setBackgroundImage(image, for: state) return } // 如果是SDK中图片,则加载SDK中图片 if let image = UIImage(named: imageStr) { base.setBackgroundImage(image, for: state) return } // 都不存在,则置为nil base.setBackgroundImage(placeholder ?? .brokenNetworkImage, for: state) return } base.kf.setBackgroundImage( with: imageURL, for: state, placeholder: placeholder, options: kNetworkImageFailureOptions, completionHandler: { result in switch result { case let .success(imageinfo): completionHandler?(imageinfo.image, nil) case let .failure(error): completionHandler?(nil, error) } } ) } } enum HeadPic { static let placeholder = UIImage(named: "UserIcon/1") ?? UIImage() static func isRemote(_ value: String) -> Bool { let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() return trimmed.hasPrefix("http://") || trimmed.hasPrefix("https://") } static func resolved(_ values: String?...) -> String { let trimmed = values .compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) } .filter { !$0.isEmpty } if let remote = trimmed.first(where: { isRemote($0) }) { return remote } return trimmed.first ?? "" } static func localImage(_ value: String) -> UIImage { let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return placeholder } return UIImage(named: "UserIcon/\(trimmed)") ?? placeholder } static func remoteURL(for value: String) -> URL? { let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines) guard isRemote(trimmed) else { return nil } return trimmed.imageURL ?? URL(string: trimmed) } static func image(for value: String) -> UIImage { guard let url = remoteURL(for: value) else { return localImage(value) } let key = url.cacheKey if let cached = ImageCache.default.retrieveImageInMemoryCache(forKey: key) { return cached } return UIImage() } static func load(_ value: String, completion: @escaping (UIImage) -> Void) { guard let url = remoteURL(for: value) else { completion(localImage(value)) return } KingfisherManager.shared.retrieveImage(with: url) { result in let image: UIImage switch result { case let .success(value): image = value.image case .failure: image = .brokenNetworkImage } DispatchQueue.main.async { completion(image) } } } } extension UIImageView { func setHeadPic(_ value: String?) { let trimmed = (value ?? "").trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { kf.cancelDownloadTask() image = HeadPic.placeholder return } if let url = HeadPic.remoteURL(for: trimmed) { kf.cancelDownloadTask() kf.setImage(with: url, placeholder: nil, options: kNetworkImageFailureOptions) } else { kf.cancelDownloadTask() image = HeadPic.localImage(trimmed) } } }