KMConvertPDFManager.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //
  2. // KMConvertPDFManager.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2022/12/19.
  6. //
  7. import Cocoa
  8. class KMConvertPDFPage: CPDFPage {
  9. var url: URL?
  10. override func draw(with box: CPDFDisplayBox, to context: CGContext!) {
  11. super.draw(with: box, to: context)
  12. if (context != nil) {
  13. NSGraphicsContext.current = NSGraphicsContext.init(cgContext: context, flipped: false)
  14. }
  15. drawImageTocontext(context)
  16. }
  17. func drawImageTocontext(_ context: CGContext) -> Void {
  18. let blankA4Size = CGSize(width: 595, height: 842)
  19. let imageCIImage = CIImage(data: try! Data(contentsOf: url!))
  20. let imagesize = imageCIImage?.extent.size
  21. var rect = NSZeroRect
  22. let image = NSImage.init(contentsOfFile: url!.path)
  23. if imagesize!.width <= blankA4Size.width && imagesize!.height <= blankA4Size.height {
  24. rect = CGRect(x: (blankA4Size.width-imagesize!.width)/2, y: (blankA4Size.height-imagesize!.height)/2, width: imagesize!.width, height: imagesize!.height)
  25. } else {
  26. let scanl = min(blankA4Size.width/imagesize!.width, blankA4Size.height/imagesize!.height)
  27. rect = CGRect(x: 0, y: 0, width: imagesize!.width * scanl, height: imagesize!.height * scanl)
  28. }
  29. image?.draw(in: rect, from: NSZeroRect, operation: .sourceOver, fraction: 1.0)
  30. }
  31. }
  32. class KMConvertPDFManager: NSObject {
  33. class func convertImages(_ imagesPaths: [URL], savePath: String, completionHandler complet: @escaping (_ success: Bool, _ errorDic: [String: Any]) -> Void) -> Void {
  34. DispatchQueue.global().async {
  35. let pdf = CPDFDocument.init()
  36. let blankA4Size = CGSize(width: 595, height: 842)
  37. for url in imagesPaths {
  38. let page = KMConvertPDFPage.init()
  39. page.url = url
  40. let imageCIImage = CIImage(data: try! Data(contentsOf: url))
  41. let size = imageCIImage?.extent.size
  42. var contextSize = NSZeroSize
  43. if size!.width <= blankA4Size.width && size!.height <= blankA4Size.height {
  44. contextSize = blankA4Size
  45. } else {
  46. let scanl = min(blankA4Size.width/size!.width, blankA4Size.height/size!.height)
  47. contextSize = CGSize(width: size!.width * scanl, height: size!.height * scanl)
  48. }
  49. page.setBounds(CGRect(x: 0, y: 0, width: contextSize.width, height: contextSize.height), for: .mediaBox)
  50. pdf?.insertPageObject(page, at: pdf!.pageCount)
  51. }
  52. DispatchQueue.main.async {
  53. let isSucceed = pdf?.write(toFile: savePath)
  54. complet(isSucceed!, [:])
  55. }
  56. }
  57. }
  58. class func supportFileType() -> [String] {
  59. var supportArray = self.supportImages()
  60. if (self.isSupportConvertPages()) {
  61. supportArray += self.supportPages()
  62. } else if (self.isSupportConvertWord()) {
  63. supportArray += self.supportWord()
  64. }
  65. if (self.isSupportConvertKeynote()) {
  66. supportArray += self.supportKeynote()
  67. } else if (self.isSupportConvertPPTX()) {
  68. supportArray += self.supportPPTX()
  69. }
  70. if (self.isSupportConvertNumber()) {
  71. supportArray += self.supportNumber()
  72. } else if (self.isSupportConvertExcel()) {
  73. /**
  74. 经测试(2011版 Excel)转档成功以后地址会存在问题,暂时建议不要用
  75. **/
  76. supportArray += self.supportExcel()
  77. }
  78. return supportArray
  79. }
  80. class func convertFile(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  81. var tSavePath = savePath
  82. if (tSavePath.substring(to: 1) == "/") {
  83. tSavePath = tSavePath.substring(form: 1)
  84. }
  85. tSavePath = tSavePath.replacingOccurrences(of: "/", with: ":")
  86. var tFilePath = filePath
  87. if (tFilePath.substring(to: 1) == "/") {
  88. tFilePath = tFilePath.substring(form: 1)
  89. }
  90. tFilePath = tFilePath.replacingOccurrences(of: "/", with: ":")
  91. let exn = filePath.components(separatedBy: ".").last?.lowercased() ?? ""
  92. if (self.supportPages().contains(exn)) {
  93. if (self.supportWord().contains(exn)) {
  94. self.convertWordPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  95. } else {
  96. self.convertApplicationName("Pages", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  97. }
  98. } else if (self.supportKeynote().contains(exn)) {
  99. if (self.supportPPTX().contains(exn)) {
  100. self.convertPPTXPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  101. } else {
  102. self.convertApplicationName("Keynote", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  103. }
  104. } else if (self.supportNumber().contains(exn)) {
  105. if (self.supportExcel().contains(exn)) {
  106. self.convertExcelPath(tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  107. } else {
  108. self.convertApplicationName("Numbers", filePath: tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  109. }
  110. } else if (self.supportImages().contains(exn)) {
  111. self.convertImagePath(tFilePath, savePath: tSavePath, completionHandler: completionHandler)
  112. } else {
  113. completionHandler(false, nil)
  114. }
  115. }
  116. class func supportImages() -> [String] {
  117. return ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi"]
  118. }
  119. class func convertImagePath(_ imagePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  120. guard let image = NSImage(contentsOfFile: imagePath) else {
  121. completionHandler(false, nil)
  122. return
  123. }
  124. DispatchQueue.global().async {
  125. let pdf = PDFDocument()
  126. if let page = PDFPage(image: image) {
  127. pdf.insert(page, at: 0)
  128. let isSucceed = pdf.write(toFile: savePath)
  129. DispatchQueue.main.async {
  130. completionHandler(isSucceed, nil)
  131. }
  132. } else {
  133. completionHandler(false, nil)
  134. }
  135. }
  136. }
  137. // MARK: - convert Word
  138. class func isSupportConvertWord() -> Bool {
  139. if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft Word") {
  140. return true
  141. }
  142. return false
  143. }
  144. class func supportWord() -> [String] {
  145. return ["docx","doc"]
  146. }
  147. class func convertWordPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  148. DispatchQueue.global().async {
  149. var convertString = String(format: "set filePath to\"%@\"\n", filePath)
  150. convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath)
  151. convertString.append("tell application \"Microsoft Word\"\n")
  152. convertString.append("set isRun to running\n")
  153. convertString.append("open file filePath\n")
  154. convertString.append("save as active document file format format PDF file name savePath\n")
  155. convertString.append("close active document\n")
  156. convertString.append("if not isRun then quit\n")
  157. convertString.append("end tell\n")
  158. // let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  159. // let docScript = NSAppleScript(source: convertString)
  160. // docScript?.executeAndReturnError(dic)
  161. let dic = KMOCTool.convertOfficeFile(toPdf: convertString)
  162. DispatchQueue.main.async {
  163. completionHandler(true, dic as NSDictionary)
  164. }
  165. }
  166. }
  167. // MARK: - convert Pages
  168. class func isSupportConvertPages() -> Bool {
  169. if let _ = NSWorkspace.shared.fullPath(forApplication: "Pages") {
  170. return true
  171. }
  172. return false
  173. }
  174. class func supportPages() -> [String] {
  175. return ["pages","docx","doc","txt","rtf"]
  176. }
  177. // MARK: - convert Keynote
  178. class func isSupportConvertKeynote() -> Bool {
  179. if let _ = NSWorkspace.shared.fullPath(forApplication: "Keynote") {
  180. return true
  181. }
  182. return false
  183. }
  184. class func supportKeynote() -> [String] {
  185. return ["ppt","pptx","key"]
  186. }
  187. // MARK: - convert PPTX
  188. class func isSupportConvertPPTX() -> Bool {
  189. if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft PowerPoint") {
  190. return true
  191. }
  192. return false
  193. }
  194. class func supportPPTX() -> [String] {
  195. return ["ppt","pptx"]
  196. }
  197. class func convertPPTXPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  198. DispatchQueue.global().async {
  199. var convertString = "tell application \"Microsoft PowerPoint\"\n"
  200. convertString.append("set isRun to running\n")
  201. convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath)
  202. convertString = convertString.appendingFormat("set filePath to \"%@\"\n", filePath)
  203. convertString.append("open file filePath\n")
  204. convertString.append("save active presentation in savePath as save as PDF\n")
  205. convertString.append("if not isRun then quit\n")
  206. convertString.append("close active presentation\n")
  207. convertString.append("end tell\n")
  208. // let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  209. // let docScript = NSAppleScript(source: convertString)
  210. // docScript?.executeAndReturnError(dic)
  211. let dic = KMOCTool.convertOfficeFile(toPdf: convertString)
  212. DispatchQueue.main.async {
  213. completionHandler(true, dic as NSDictionary)
  214. }
  215. }
  216. }
  217. // MARK: - convert Numbers
  218. class func isSupportConvertNumber() -> Bool {
  219. if let _ = NSWorkspace.shared.fullPath(forApplication: "Numbers") {
  220. return true
  221. }
  222. return false
  223. }
  224. class func supportNumber() -> [String] {
  225. return ["xls","xlsx","numbers","csv"]
  226. }
  227. // MARK: - convert Excel
  228. class func isSupportConvertExcel() -> Bool {
  229. if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft Excel") {
  230. return true
  231. }
  232. return false
  233. }
  234. class func supportExcel() -> [String] {
  235. return ["xlsx","xls"]
  236. }
  237. class func convertExcelPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  238. DispatchQueue.global().async {
  239. var convertString = String(format: "set filePath to\"%@\"\n", filePath)
  240. convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath)
  241. convertString.append("set tFile to (POSIX path of filePath) as POSIX file\n")
  242. convertString.append("tell application \"Microsoft Excel\"\n")
  243. convertString.append("set isRun to running\n")
  244. convertString.append("set wkbk1 to open workbook workbook file name tFile\n")
  245. convertString.append("alias savePath\n")
  246. convertString.append("save workbook as wkbk1 filename savePath file format PDF file format with overwrite\n")
  247. convertString.append("close wkbk1 saving no\n")
  248. convertString.append("if not isRun then quit\n")
  249. convertString.append("end tell\n")
  250. // let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  251. // let docScript = NSAppleScript(source: convertString)
  252. // docScript?.executeAndReturnError(dic)
  253. let dic = KMOCTool.convertOfficeFile(toPdf: convertString)
  254. DispatchQueue.main.async {
  255. completionHandler(true, dic as NSDictionary)
  256. }
  257. }
  258. }
  259. class func convertApplicationName(_ appName: String, filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  260. DispatchQueue.global().async {
  261. var convertString = String(format: "tell application \"%@\"\n", appName)
  262. convertString.append("set isRun to running\n")
  263. convertString = convertString.appendingFormat("set in_file to \"%@\"\n", filePath)
  264. convertString = convertString.appendingFormat("set out_file to \"%@\"\n", savePath)
  265. convertString.append("set mydoc to open file in_file\n")
  266. convertString.append("export mydoc to file out_file as PDF\n")
  267. convertString.append("close mydoc saving no\n")
  268. convertString.append("if not isRun then quit\n")
  269. convertString.append("end tell")
  270. // let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  271. // let docScript = NSAppleScript(source: convertString)
  272. // docScript?.executeAndReturnError(dic)
  273. let dic = KMOCTool.convertOfficeFile(toPdf: convertString)
  274. DispatchQueue.main.async {
  275. completionHandler(true, dic as NSDictionary)
  276. }
  277. }
  278. }
  279. }