// // KMConvertPDFManager.swift // PDF Reader Pro // // Created by wanjun on 2022/12/19. // import Cocoa class KMConvertPDFPage: CPDFPage { var url: URL? override func draw(with box: CPDFDisplayBox, to context: CGContext!) { super.draw(with: box, to: context) if (context != nil) { NSGraphicsContext.current = NSGraphicsContext.init(cgContext: context, flipped: false) } drawImageTocontext(context) } func drawImageTocontext(_ context: CGContext) -> Void { let blankA4Size = CGSize(width: 595, height: 842) let imageCIImage = CIImage(data: try! Data(contentsOf: url!)) let imagesize = imageCIImage?.extent.size var rect = NSZeroRect let image = NSImage.init(contentsOfFile: url!.path) if imagesize!.width <= blankA4Size.width && imagesize!.height <= blankA4Size.height { rect = CGRect(x: (blankA4Size.width-imagesize!.width)/2, y: (blankA4Size.height-imagesize!.height)/2, width: imagesize!.width, height: imagesize!.height) } else { let scanl = min(blankA4Size.width/imagesize!.width, blankA4Size.height/imagesize!.height) rect = CGRect(x: 0, y: 0, width: imagesize!.width * scanl, height: imagesize!.height * scanl) } image?.draw(in: rect, from: NSZeroRect, operation: .sourceOver, fraction: 1.0) } } class KMConvertPDFManager: NSObject { class func convertImages(_ imagesPaths: [URL], savePath: String, completionHandler complet: @escaping (_ success: Bool, _ errorDic: [String: Any]) -> Void) -> Void { DispatchQueue.global().async { let pdf = CPDFDocument.init() let blankA4Size = CGSize(width: 595, height: 842) for url in imagesPaths { let page = KMConvertPDFPage.init() page.url = url let imageCIImage = CIImage(data: try! Data(contentsOf: url)) let size = imageCIImage?.extent.size var contextSize = NSZeroSize if size!.width <= blankA4Size.width && size!.height <= blankA4Size.height { contextSize = blankA4Size } else { let scanl = min(blankA4Size.width/size!.width, blankA4Size.height/size!.height) contextSize = CGSize(width: size!.width * scanl, height: size!.height * scanl) } page.setBounds(CGRect(x: 0, y: 0, width: contextSize.width, height: contextSize.height), for: .mediaBox) pdf?.insertPageObject(page, at: pdf!.pageCount) } DispatchQueue.main.async { let isSucceed = pdf?.write(toFile: savePath) complet(isSucceed!, [:]) } } } class func supportFileType() -> [String] { var supportArray = self.supportImages() if (self.isSupportConvertPages()) { supportArray += self.supportPages() } else if (self.isSupportConvertWord()) { supportArray += self.supportWord() } if (self.isSupportConvertKeynote()) { supportArray += self.supportKeynote() } else if (self.isSupportConvertPPTX()) { supportArray += self.supportPPTX() } if (self.isSupportConvertNumber()) { supportArray += self.supportNumber() } else if (self.isSupportConvertExcel()) { /** 经测试(2011版 Excel)转档成功以后地址会存在问题,暂时建议不要用 **/ supportArray += self.supportExcel() } return supportArray } class func convertFile(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { var tSavePath = savePath if (tSavePath.substring(to: 1) == "/") { tSavePath = tSavePath.substring(form: 1) } tSavePath = tSavePath.replacingOccurrences(of: "/", with: ":") var tFilePath = filePath if (tFilePath.substring(to: 1) == "/") { tFilePath = tFilePath.substring(form: 1) } tFilePath = tFilePath.replacingOccurrences(of: "/", with: ":") let exn = filePath.components(separatedBy: ".").last?.lowercased() ?? "" if (self.supportPages().contains(exn)) { if (self.supportWord().contains(exn)) { self.convertWordPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler) } else { self.convertApplicationName("Pages", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler) } } else if (self.supportKeynote().contains(exn)) { if (self.supportPPTX().contains(exn)) { self.convertPPTXPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler) } else { self.convertApplicationName("Keynote", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler) } } else if (self.supportNumber().contains(exn)) { if (self.supportExcel().contains(exn)) { self.convertExcelPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler) } else { self.convertApplicationName("Numbers", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler) } } else if (self.supportImages().contains(exn)) { self.convertImagePath(tFilePath, savePath: tSavePath, completionHandler: completionHandler) } else { completionHandler(false, nil) } } class func supportImages() -> [String] { return ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi"] } class func convertImagePath(_ imagePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { guard let image = NSImage(contentsOfFile: imagePath) else { completionHandler(false, nil) return } DispatchQueue.global().async { let pdf = PDFDocument() if let page = PDFPage(image: image) { pdf.insert(page, at: 0) let isSucceed = pdf.write(toFile: savePath) DispatchQueue.main.async { completionHandler(isSucceed, nil) } } else { completionHandler(false, nil) } } } // MARK: - convert Word class func isSupportConvertWord() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft Word") { return true } return false } class func supportWord() -> [String] { return ["docx","doc"] } class func convertWordPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { DispatchQueue.global().async { var convertString = String(format: "set filePath to\"%@\"\n", filePath) convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath) convertString.append("tell application \"Microsoft Word\"\n") convertString.append("set isRun to running\n") convertString.append("open file filePath\n") convertString.append("save as active document file format format PDF file name savePath\n") convertString.append("close active document\n") convertString.append("if not isRun then quit\n") convertString.append("end tell\n") var dic: NSDictionary? let docScript = NSAppleScript(source: convertString) docScript?.executeAndReturnError(&dic) // let dic = KMOCTool.convertOfficeFile(toPdf: convertString) DispatchQueue.main.async { completionHandler(true, dic) } } } // MARK: - convert Pages class func isSupportConvertPages() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Pages") { return true } return false } class func supportPages() -> [String] { return ["pages","docx","doc","txt","rtf"] } // MARK: - convert Keynote class func isSupportConvertKeynote() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Keynote") { return true } return false } class func supportKeynote() -> [String] { return ["ppt","pptx","key"] } // MARK: - convert PPTX class func isSupportConvertPPTX() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft PowerPoint") { return true } return false } class func supportPPTX() -> [String] { return ["ppt","pptx"] } class func convertPPTXPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { DispatchQueue.global().async { var convertString = "tell application \"Microsoft PowerPoint\"\n" convertString.append("set isRun to running\n") convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath) convertString = convertString.appendingFormat("set filePath to \"%@\"\n", filePath) convertString.append("open file filePath\n") convertString.append("save active presentation in savePath as save as PDF\n") convertString.append("if not isRun then quit\n") convertString.append("close active presentation\n") convertString.append("end tell\n") var dic: NSDictionary? let docScript = NSAppleScript(source: convertString) docScript?.executeAndReturnError(&dic) // let dic = KMOCTool.convertOfficeFile(toPdf: convertString) DispatchQueue.main.async { completionHandler(true, dic) } } } // MARK: - convert Numbers class func isSupportConvertNumber() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Numbers") { return true } return false } class func supportNumber() -> [String] { return ["xls","xlsx","numbers","csv"] } // MARK: - convert Excel class func isSupportConvertExcel() -> Bool { if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft Excel") { return true } return false } class func supportExcel() -> [String] { return ["xlsx","xls"] } class func convertExcelPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { DispatchQueue.global().async { var convertString = String(format: "set filePath to\"%@\"\n", filePath) convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath) convertString.append("set tFile to (POSIX path of filePath) as POSIX file\n") convertString.append("tell application \"Microsoft Excel\"\n") convertString.append("set isRun to running\n") convertString.append("set wkbk1 to open workbook workbook file name tFile\n") convertString.append("alias savePath\n") convertString.append("save workbook as wkbk1 filename savePath file format PDF file format with overwrite\n") convertString.append("close wkbk1 saving no\n") convertString.append("if not isRun then quit\n") convertString.append("end tell\n") var dic: NSDictionary? let docScript = NSAppleScript(source: convertString) docScript?.executeAndReturnError(&dic) // let dic = KMOCTool.convertOfficeFile(toPdf: convertString) DispatchQueue.main.async { completionHandler(true, dic) } } } class func convertApplicationName(_ appName: String, filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) { DispatchQueue.global().async { var convertString = String(format: "tell application \"%@\"\n", appName) convertString.append("set isRun to running\n") convertString = convertString.appendingFormat("set in_file to \"%@\"\n", filePath) convertString = convertString.appendingFormat("set out_file to \"%@\"\n", savePath) convertString.append("set mydoc to open file in_file\n") convertString.append("export mydoc to file out_file as PDF\n") convertString.append("close mydoc saving no\n") convertString.append("if not isRun then quit\n") convertString.append("end tell") var dic: NSDictionary? let docScript = NSAppleScript(source: convertString) docScript?.executeAndReturnError(&dic) // let dic = KMOCTool.convertOfficeFile(toPdf: convertString) DispatchQueue.main.async { completionHandler(true, dic) } } } }