// // UIImage+Ex.swift // TSLiveWallpaper // // Created by 100Years on 2024/12/23. // public extension UIImage { var width: CGFloat { size.width } var height: CGFloat { size.height } public func normalizedImage() -> UIImage? { if imageOrientation == .up { return self } return repaintImage() } public func repaintImage() -> UIImage? { let format = UIGraphicsImageRendererFormat() format.opaque = false format.scale = scale let renderer = UIGraphicsImageRenderer(size: size, format: format) let image = renderer.image { context in draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) } return image } public func scaleToFillSize(size: CGSize, mode: UIView.ContentMode = .scaleToFill, scale: CGFloat = 0) -> UIImage? { if __CGSizeEqualToSize(self.size, size) { return self } let rect: CGRect let rendererSize: CGSize if mode == .scaleToFill { let isEqualRatio = size.width / size.height == width / height if isEqualRatio { rendererSize = size rect = CGRect(origin: .zero, size: size) }else { let scale = size.width / width var scaleHeight = scale * height var scaleWidth = size.width if scaleHeight < size.height { scaleWidth = size.height / scaleHeight * size.width scaleHeight = size.height } rendererSize = .init(width: scaleWidth, height: scaleHeight) rect = .init(origin: .zero, size: rendererSize) } }else { rendererSize = size if mode == .scaleAspectFit { rect = CGRect(origin: .zero, size: size) }else { var x: CGFloat = 0 var y: CGFloat = 0 let scale = size.width / width var scaleWidth = size.width var scaleHeight = scale * height if scaleHeight < size.height { scaleWidth = size.height / scaleHeight * scaleWidth scaleHeight = size.height } if scaleWidth < size.width { scaleHeight = size.width / scaleWidth * scaleHeight scaleWidth = size.width } x = -(scaleWidth - size.width) / 2 y = -(scaleHeight - size.height) / 2 rect = CGRect( x: x, y: y, width: scaleWidth, height: scaleHeight ) } } let format = UIGraphicsImageRendererFormat() format.opaque = false format.scale = scale == 0 ? self.scale : scale let renderer = UIGraphicsImageRenderer(size: rendererSize, format: format) let image = renderer.image { context in draw(in: rect) } return image } public var pngImage:UIImage?{ // 将 UIImage 转为 PNG Data guard let pngData = self.pngData() else { print("Failed to convert WebP image to PNG data.") return nil } // 使用 PNG Data 创建新的 UIImage return UIImage(data: pngData) } } public extension UIImage { /// 将颜色转换为 UIImage /// - Parameters: /// - color: 目标颜色 /// - size: 图片尺寸(默认 1x1) /// - Returns: 转换后的 UIImage public static func colorFrom(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage? { // 创建一个矩形 let rect = CGRect(origin: .zero, size: size) // 开始图形上下文 UIGraphicsBeginImageContextWithOptions(size, false, 0) // 设置颜色填充 color.setFill() UIRectFill(rect) // 获取生成的图片 let image = UIGraphicsGetImageFromCurrentImageContext() // 结束图形上下文 UIGraphicsEndImageContext() return image } public func resizableImage(capInsets:UIEdgeInsets) -> UIImage{ return resizableImage(withCapInsets: capInsets, resizingMode: .stretch) } // 创建纯色图片 convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) { let rect = CGRect(origin: .zero, size: size) UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) color.setFill() UIRectFill(rect) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() guard let cgImage = image?.cgImage else { return nil } self.init(cgImage: cgImage) } // 创建圆形图片 static func circle(diameter: CGFloat, color: UIColor) -> UIImage { let size = CGSize(width: diameter, height: diameter) let renderer = UIGraphicsImageRenderer(size: size) return renderer.image { context in let rect = CGRect(origin: .zero, size: size) color.setFill() UIBezierPath(ovalIn: rect).fill() } } } public extension UIImage { var mirror: UIImage { // guard TSConfig.appLanguage.hasPrefix("ar"), let cgImage = self.cgImage else { guard let cgImage = self.cgImage else { return self } let image = UIImage(cgImage: cgImage, scale: self.scale, orientation: Orientation.upMirrored) return image.withRenderingMode(self.renderingMode) } func resize(to size: CGSize) -> UIImage? { UIGraphicsBeginImageContextWithOptions(size, false, 0.0) self.draw(in: CGRect(origin: .zero, size: size)) let resizedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return resizedImage } func cropped(to aspectRatio: CGFloat) -> UIImage? { let originalSize = self.size let targetSize: CGSize if originalSize.width > originalSize.height { // 宽度大于高度,裁剪宽度 targetSize = CGSize(width: originalSize.height, height: originalSize.height) } else { // 高度大于宽度,裁剪高度 targetSize = CGSize(width: originalSize.width, height: originalSize.width) } let cropRect = CGRect( x: (originalSize.width - targetSize.width) / 2, y: (originalSize.height - targetSize.height) / 2, width: targetSize.width, height: targetSize.height ) if let cgImage = self.cgImage?.cropping(to: cropRect) { return UIImage(cgImage: cgImage, scale: self.scale, orientation: self.imageOrientation) } return nil } /// 判断图片是否大于指定大小(默认10MB) func isLargerThan(byteSize: Int) -> Bool { // // 优先尝试JPEG压缩(更接近实际文件大小) // if let jpegData = self.jpegData(compressionQuality: 1.0) { // print("JPEG格式大小: \(Double(jpegData.count) / (1024 * 1024)) MB") // return jpegData.count > byteSize // } // 透明图片回退到PNG if let pngData = self.pngData() { print("PNG格式大小: \(Double(pngData.count) / (1024 * 1024)) MB") return pngData.count > byteSize } return false // 无法获取数据时默认不限制 } } //旋转图片 public extension UIImage { /// 按角度旋转图片 /// - Parameter degrees: 旋转正数为顺时针,负数为逆时针) /// - Returns: 旋转后的新图片 func rotated(byDegrees degrees: CGFloat) -> UIImage? { let radians = degrees * .pi / 180 return rotated(byRadians: radians) } /// 按弧度旋转图片 /// - Parameter radians: 旋转弧度 /// - Returns: 旋转后的新图片 func rotated(byRadians radians: CGFloat) -> UIImage? { // 计算旋转后的新边界大小 let rotatedSize = CGRect(origin: .zero, size: size) .applying(CGAffineTransform(rotationAngle: radians)) .integral.size // 开始图形上下文 UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale) guard let context = UIGraphicsGetCurrentContext() else { return nil } // 移动和旋转坐标系 context.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2) context.rotate(by: radians) // 绘制图像 draw(in: CGRect( x: -size.width / 2, y: -size.height / 2, width: size.width, height: size.height )) // 获取旋转后的图像 let rotatedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return rotatedImage } /// 固定角度旋转(90度、180度、270度) /// - Parameter rotation: 旋转角度 /// - Returns: 旋转后的新图片 func rotated(by rotation: Rotation) -> UIImage? { switch rotation { case .degrees90: return rotated(byDegrees: 90) case .degrees180: return rotated(byDegrees: 180) case .degrees270: return rotated(byDegrees: 270) } } // MARK: - 辅助类型 enum Rotation { case degrees90 case degrees180 case degrees270 } /// 保存图片到文件系统 /// - Parameters: /// - url: 目标URL /// - compressionQuality: JPEG压缩质量(0.0-1.0) /// - Throws: 可能抛出错误 func saveToFile(at url: URL, compressionQuality: CGFloat = 1.0) { guard let data = self.jpegData(compressionQuality: compressionQuality) else { debugPrint("无法转换为JPEG数据") return } do { try data.write(to: url) } catch { debugPrint(error) } } } public extension UIImage { // 压缩图片到指定尺寸 func compressImageSize(to size: CGSize) -> UIImage { let targetSize = size if self.size.width > targetSize.width || self.size.height > targetSize.height { return kf.resize(to: targetSize) } return self } }