KMConvertPDFManager.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //
  2. // KMConvertPDFManager.swift
  3. // PDF Master
  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. DispatchQueue.main.async {
  162. completionHandler(true, dic?.pointee)
  163. }
  164. }
  165. }
  166. // MARK: - convert Pages
  167. class func isSupportConvertPages() -> Bool {
  168. if let _ = NSWorkspace.shared.fullPath(forApplication: "Pages") {
  169. return true
  170. }
  171. return false
  172. }
  173. class func supportPages() -> [String] {
  174. return ["pages","docx","doc","txt","rtf"]
  175. }
  176. // MARK: - convert Keynote
  177. class func isSupportConvertKeynote() -> Bool {
  178. if let _ = NSWorkspace.shared.fullPath(forApplication: "Keynote") {
  179. return true
  180. }
  181. return false
  182. }
  183. class func supportKeynote() -> [String] {
  184. return ["ppt","pptx","key"]
  185. }
  186. // MARK: - convert PPTX
  187. class func isSupportConvertPPTX() -> Bool {
  188. if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft PowerPoint") {
  189. return true
  190. }
  191. return false
  192. }
  193. class func supportPPTX() -> [String] {
  194. return ["ppt","pptx"]
  195. }
  196. class func convertPPTXPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  197. DispatchQueue.global().async {
  198. var convertString = "tell application \"Microsoft PowerPoint\"\n"
  199. convertString.append("set isRun to running\n")
  200. convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath)
  201. convertString = convertString.appendingFormat("set filePath to \"%@\"\n", filePath)
  202. convertString.append("open file filePath\n")
  203. convertString.append("save active presentation in savePath as save as PDF\n")
  204. convertString.append("if not isRun then quit\n")
  205. convertString.append("close active presentation\n")
  206. convertString.append("end tell\n")
  207. let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  208. let docScript = NSAppleScript(source: convertString)
  209. docScript?.executeAndReturnError(dic)
  210. DispatchQueue.main.async {
  211. completionHandler(true, dic?.pointee)
  212. }
  213. }
  214. }
  215. // MARK: - convert Numbers
  216. class func isSupportConvertNumber() -> Bool {
  217. if let _ = NSWorkspace.shared.fullPath(forApplication: "Numbers") {
  218. return true
  219. }
  220. return false
  221. }
  222. class func supportNumber() -> [String] {
  223. return ["xls","xlsx","numbers","csv"]
  224. }
  225. // MARK: - convert Excel
  226. class func isSupportConvertExcel() -> Bool {
  227. if let _ = NSWorkspace.shared.fullPath(forApplication: "Microsoft Excel") {
  228. return true
  229. }
  230. return false
  231. }
  232. class func supportExcel() -> [String] {
  233. return ["xlsx","xls"]
  234. }
  235. class func convertExcelPath(_ filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  236. DispatchQueue.global().async {
  237. var convertString = String(format: "set filePath to\"%@\"\n", filePath)
  238. convertString = convertString.appendingFormat("set savePath to \"%@\"\n", savePath)
  239. convertString.append("set tFile to (POSIX path of filePath) as POSIX file\n")
  240. convertString.append("tell application \"Microsoft Excel\"\n")
  241. convertString.append("set isRun to running\n")
  242. convertString.append("set wkbk1 to open workbook workbook file name tFile\n")
  243. convertString.append("alias savePath\n")
  244. convertString.append("save workbook as wkbk1 filename savePath file format PDF file format with overwrite\n")
  245. convertString.append("close wkbk1 saving no\n")
  246. convertString.append("if not isRun then quit\n")
  247. convertString.append("end tell\n")
  248. let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  249. let docScript = NSAppleScript(source: convertString)
  250. docScript?.executeAndReturnError(dic)
  251. DispatchQueue.main.async {
  252. completionHandler(true, dic?.pointee)
  253. }
  254. }
  255. }
  256. class func convertApplicationName(_ appName: String, filePath: String, savePath: String, completionHandler: @escaping ((Bool, NSDictionary?) -> Void)) {
  257. DispatchQueue.global().async {
  258. var convertString = String(format: "tell application \"%@\"\n", appName)
  259. convertString.append("set isRun to running\n")
  260. convertString = convertString.appendingFormat("set in_file to \"%@\"\n", filePath)
  261. convertString = convertString.appendingFormat("set out_file to \"%@\"\n", savePath)
  262. convertString.append("set mydoc to open file in_file\n")
  263. convertString.append("export mydoc to file out_file as PDF\n")
  264. convertString.append("close mydoc saving no\n")
  265. convertString.append("if not isRun then quit\n")
  266. convertString.append("end tell")
  267. let dic: AutoreleasingUnsafeMutablePointer<NSDictionary?>? = nil
  268. let docScript = NSAppleScript(source: convertString)
  269. docScript?.executeAndReturnError(dic)
  270. DispatchQueue.main.async {
  271. completionHandler(true, dic?.pointee)
  272. }
  273. }
  274. }
  275. }