123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- //
- // KMImageToPDFManager.swift
- // PDF Master
- //
- // Created by lizhe on 2022/12/6.
- //
- import Cocoa
- import ComPDFKit
- typealias KMImageToPDFManagerCompletion = (_ success: Bool, _ savePath: String?, _ errors: Array<String>?, _ OCRerrors: Array<String>?) -> Void
- typealias KMImageToPDFManagerProgress = (_ status: KMImageToPDFStatus) -> Void
- enum KMImageToPDFStatus: String {
- case unknow
- case prepareConversion
- case conversioning
- }
- class KMImageToPDFManager: NSObject {
- //回调
- var completion: KMImageToPDFManagerCompletion? = nil
- var progress: KMImageToPDFManagerProgress?
- /**
- 参数
- */
- var status: KMImageToPDFStatus = .unknow //当前manager状态
- var model: KMImageToPDFChooseModel? //内部数据
- var conversionIndex: Int? //转换下标
-
- //懒加载数组
- lazy var errors: Array<String> = []
- lazy var OCRerrors: Array<String> = []
-
- //单例
- public static let manager = KMImageToPDFManager()
- //MARK: public
- /**
- 导出PDF
- */
- func exportPDF(model: KMImageToPDFChooseModel, completion: KMImageToPDFManagerCompletion?, progress: @escaping KMImageToPDFManagerProgress) {
- if status == .unknow {
- self.progress = progress
- //变量
- self.model = model
- self.completion = completion
-
- //移除缓存数据
- self.errors.removeAll()
- self.OCRerrors.removeAll()
-
- //基本参数
- // let exportFilePath = self.model?.exportFilePath
- // let password = self.model?.password
- let options = self.model?.options!
- let exportPDFType = self.model?.exportPDFType
-
- if (options!.contains(.OCR)) {
- //TODO: OCR部分待SDK提供
- KMPrint("OCR 暂未实现")
- } else if (options!.contains(.PDF)) {
- if (exportPDFType == .new) {
- self.creatPDF(model: self.model!, completion: completion)
- } else if (exportPDFType == .merge) {
- self.mergePDF(model: self.model!, completion: completion)
- } else if (exportPDFType == .insert) {
- self.mergePDF(model: self.model!, completion: completion)
- }
- } else {
- if completion != nil {
- completion!(false, model.exportFilePath, model.filePaths(), nil)
- }
- }
- } else {
- if completion != nil {
- completion!(false, model.exportFilePath, model.filePaths(), nil)
- }
- }
- }
-
- func cancel () {
-
- }
-
- //MARK: private
- /**
- 创建PDF
- */
- private func creatPDF(model: KMImageToPDFChooseModel, completion: KMImageToPDFManagerCompletion?) {
- if status == .unknow {
- status = .conversioning
- let savePath = model.exportFilePath
-
- for imageFilePath in model.imageFilePaths! {
- let success = creatPDFConversion(filePath: imageFilePath.filePath, savePath: savePath!)
- KMPrint(success)
- if success == false {
- imageFilePath.state = .error
- self.errors.append(imageFilePath.filePath)
- } else {
- imageFilePath.state = .success
- }
-
- if (self.progress != nil) {
- self.progress!(self.status)
- }
- }
-
- status = .unknow
-
- if (self.progress != nil) {
- self.progress!(self.status)
- }
-
- if completion != nil {
- completion!(true, model.exportFilePath, self.errors, nil)
- }
- } else {
- if completion != nil {
- completion!(false, model.exportFilePath, model.filePaths(), nil)
- }
- }
- }
-
- private func creatPDFConversion(filePath: String, savePath: String) -> Bool {
- let imageName = NSString(string: NSString(string: filePath).lastPathComponent).deletingPathExtension
-
- let path = self.fetchDifferentFilePath(filePath: savePath + "/" + imageName + ".pdf")
- let document = CPDFDocument.init()
- var success = false
-
- // //系统
- // let document = PDFDocument.init()
- // let pdfPage = PDFPage.init(image: NSImage(contentsOfFile: filePath)!)
- // document.insert(pdfPage!, at: 0)
- // success = document.write(toFile: path)
-
- let jpgPath = self.imageToJPG(filePath: filePath, savePath: savePath)
-
- //FIXME: 无法插入图片
- let image = NSImage(contentsOfFile: jpgPath)
- if image != nil {
- let insertPageSuccess = document?.insertPage(image!.size, withImage: jpgPath, at: document!.pageCount)
- if insertPageSuccess != nil {
- KMPrint("插入成功")
- //信号量控制异步
- let semaphore = DispatchSemaphore(value: 0)
- DispatchQueue.global().async {
- success = ((document?.write(toFile: path)) != nil)
- semaphore.signal()
- }
- semaphore.wait()
- } else {
- KMPrint("插入失败")
- }
- } else {
- KMPrint("插入失败")
- }
- return success
- }
-
- /**
- 合并PDF
- */
- private func mergePDF(model: KMImageToPDFChooseModel, completion: KMImageToPDFManagerCompletion?) {
- if status == .unknow {
- status = .conversioning
- //基本参数
- let exportFilePath = self.model?.exportFilePath
- let insetFilePath = self.model?.insertFilePath
- let password = self.model?.password
- let exportPDFType = self.model?.exportPDFType
- let imageFilePaths = self.model?.imageFilePaths
- var conversionIndex: Int = 0
- var document: CPDFDocument!
-
- /**
- * 获取文件路径
- * 如果是插入无需调整
- * 如果是新增 需排除文件同名
- */
- let filePath = (exportPDFType == .insert) ? insetFilePath : self.fetchDifferentFilePath(filePath: (exportFilePath?.appending("/Untitled.pdf"))!)
-
- //如果是插入现有PDF,需输入密码
- if exportPDFType == .insert {
- document = CPDFDocument.init(url: URL(fileURLWithPath: filePath!))!
- document.unlock(withPassword: password!)
- } else if exportPDFType == .merge {
- document = CPDFDocument.init()
- }
- //遍历图片文件
- for imageData in imageFilePaths! {
- imageData.state = .loading
- var isDirectory: ObjCBool = false
- if (FileManager.default.fileExists(atPath: imageData.filePath, isDirectory: &isDirectory) &&
- !isDirectory.boolValue) {
- let image = NSImage(contentsOfFile: imageData.filePath)
- if image != nil {
- let success = document?.insertPage(image!.size, withImage: imageData.filePath, at: UInt(conversionIndex))
- if success! {
- imageData.state = .success
- } else {
- imageData.state = .error
- if image?.size.width != 0 && image?.size.height != 0 {
- document.insertPage(image!.size, at: UInt(conversionIndex))
- } else {
- document.insertPage(CGSizeZero, at: UInt(conversionIndex))
- }
- }
- } else {
- imageData.state = .error
- document.insertPage(CGSizeZero, at: UInt(conversionIndex))
- }
- }
- conversionIndex += 1
-
- if (self.progress != nil) {
- self.progress!(self.status)
- }
- }
-
- //异步处理
- DispatchQueue.global().async { [unowned self] in
- var success = false
- if document!.pageCount >= 1 {
- if (document!.isEncrypted) {
- var attributes: [CPDFDocumentWriteOption : String] = [:]
- attributes[CPDFDocumentWriteOption.ownerPasswordOption] = password
- attributes[CPDFDocumentWriteOption.userPasswordOption] = password
- success = document.write(to: URL(string: filePath!), withOptions: attributes)
- } else {
- success = document.write(toFile: filePath!)
- }
- }
-
- if !success {
- self.errors.append(NSString(string: filePath!).lastPathComponent)
- }
-
- self.status = .unknow
- // 回到主线程异步
- DispatchQueue.main.async {
- if (self.progress != nil) {
- self.progress!(self.status)
- }
-
- if completion != nil {
- completion!(true, filePath, self.errors, self.OCRerrors)
- }
- }
- }
- } else {
- if completion != nil {
- completion!(false, model.exportFilePath, model.filePaths(), nil)
- }
- }
- }
-
- //获取不同文件路径
- func fetchDifferentFilePath(filePath: String) -> String {
- var resultFilePath = filePath
- var index: Int = 0
- while (FileManager.default.fileExists(atPath: resultFilePath)) {
- index += 1
- let path = NSString(string: filePath).deletingPathExtension + "(" + String(index) + ")"
- resultFilePath = NSString(string: path).appendingPathExtension(NSString(string: filePath).pathExtension)!
- }
-
- return resultFilePath;
- }
-
- // 图片转PNG
- func imageToJPG(filePath: String, savePath: String) -> String {
- if NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "png" ||
- NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "PNG" {
- let imageName = NSString(string: NSString(string: filePath).lastPathComponent).deletingPathExtension
- let jpgPath = self.fetchDifferentFilePath(filePath: savePath + "/" + imageName + ".jpg")
- if (!FileManager.default.fileExists(atPath: jpgPath as String)) {
- FileManager.default.createFile(atPath: jpgPath as String, contents: nil)
- }
- // 加载 PNG 图像
- guard let pngImage = NSImage(contentsOfFile: filePath) else {
- KMPrint("Failed to load PNG image")
- return filePath
- }
- // 创建 NSBitmapImageRep 对象,并将 PNG 图像绘制到其中
- let bitmap = NSBitmapImageRep(data: pngImage.tiffRepresentation!)
- let rect = NSRect(origin: .zero, size: bitmap!.size)
- bitmap?.draw(in: rect)
- // 将 PNG 图像数据转换为 JPG 图像数据
- guard let jpgData = bitmap?.representation(using: .jpeg, properties: [:]) else {
- KMPrint("Failed to convert PNG to JPG")
- return filePath
- }
- // 保存 JPG 图像数据到文件
- let fileURL = URL(fileURLWithPath: jpgPath)
- do {
- try jpgData.write(to: fileURL)
- KMPrint("JPG image saved successfully")
- return fileURL.path
- } catch {
- KMPrint("Failed to save JPG image: \(error.localizedDescription)")
- return filePath
- }
- }
-
- return filePath
- }
- }
|