// // AssetExtractor.swift // MNNLLMiOS // // Created by 游薪渝(揽清) on 2025/1/10. // import Foundation import ImageIO import UIKit class AssetExtractor { static func copyFileToTmpDirectory(from sourceUrl: URL, fileName: String) -> URL? { let fileManager = FileManager.default let tempDirectory = fileManager.temporaryDirectory let destinationUrl = tempDirectory.appendingPathComponent(fileName) // Ensure source exists guard fileManager.fileExists(atPath: sourceUrl.path) else { print("Source file does not exist at: \(sourceUrl.path)") return nil } // If file already exists in tmp, reuse it to avoid redundant copies if fileManager.fileExists(atPath: destinationUrl.path) { print("File already exists at: \(destinationUrl.path)") return destinationUrl } do { try fileManager.copyItem(at: sourceUrl, to: destinationUrl) print("File successfully copied to: \(destinationUrl.path)") return destinationUrl } catch { print("Error copying file: \(error.localizedDescription)") return nil } } /// Creates a local URL to extract an image from the Asset directory and save it to the cache directory. /// - Parameter name: The name of the image resource. /// - Returns: A local URL (if the image is successfully saved). static func createLocalUrl(forImageNamed name: String, withExtension fileExtension: String = "png") -> URL? { let fileManager = FileManager.default let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0] let url = cacheDirectory.appendingPathComponent("\(name).\(fileExtension)") if fileManager.fileExists(atPath: url.path) { return url } guard let image = UIImage(named: name) else { print("Error: Image named \(name) not found in assets.") return nil } guard let data: Data = { if fileExtension.lowercased() == "png" { return image.pngData() } else if fileExtension.lowercased() == "jpg" || fileExtension.lowercased() == "jpeg" { return image.jpegData(compressionQuality: 1.0) // High quality JPEG } else { print("Error: Unsupported file extension \(fileExtension).") return nil } }() else { print("Error: Unable to convert image \(name) to data.") return nil } do { try data.write(to: url) print("File saved to: \(url.path)") return url } catch { print("Error: Unable to write file to \(url.path). Error: \(error)") return nil } } static func convertHEICToJPG(heicUrl: URL) -> URL? { guard let imageSource = CGImageSourceCreateWithURL(heicUrl as CFURL, nil), let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else { print("Failed to load HEIC image.") return nil } let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any] let orientation = properties?[kCGImagePropertyOrientation as String] as? UInt var uiImage = UIImage(cgImage: cgImage) if let orientation = orientation { uiImage = uiImage.imageRotatedByDegrees(degrees: orientation) } let jpegData = uiImage.jpegData(compressionQuality: 0.8) let jpgUrl = heicUrl.deletingPathExtension().appendingPathExtension("jpg") do { try jpegData?.write(to: jpgUrl) print("HEIC successfully converted to JPG and saved to: \(jpgUrl.path)") return jpgUrl } catch { print("Failed to save JPEG image: \(error.localizedDescription)") return nil } } } extension UIImage { func imageRotatedByDegrees(degrees: UInt) -> UIImage { var angle: CGFloat = 0.0 switch degrees { case 1: angle = .pi / 2 // 90 degrees case 3: angle = .pi // 180 degrees case 6: angle = .pi / 2 // 90 degrees case 8: angle = -(.pi / 2) // -90 degrees default: break } UIGraphicsBeginImageContext(size) guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { UIGraphicsEndImageContext() return self } context.translateBy(x: size.width / 2, y: size.height / 2) context.rotate(by: angle) context.scaleBy(x: 1.0, y: -1.0) context.draw(cgImage, in: CGRect(x: -size.width / 2, y: -size.height / 2, width: size.width, height: size.height)) let rotatedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return rotatedImage ?? self } }