KMAIOpenPDFFilesVC.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. //
  2. // KMAIOpenPDFFilesVC.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2023/5/22.
  6. //
  7. import Cocoa
  8. class KMAIOpenPDFFilesVC: NSViewController {
  9. @IBOutlet weak var openPDFFilesLabel: NSTextField!
  10. @IBOutlet weak var openPDFFilesImageView: NSImageView!
  11. @IBOutlet weak var selectYourFilesBox: KMBox!
  12. @IBOutlet weak var selectYourFilesLabel: NSTextField!
  13. @IBOutlet weak var selectYourFilesImageView: NSImageView!
  14. @IBOutlet weak var orDropFilesHereToOpenLabel: NSTextField!
  15. @IBOutlet weak var creatPDFLabel: NSTextField!
  16. @IBOutlet weak var newFromFilesLabel: NSTextField!
  17. @IBOutlet weak var newFromFilesImageView: NSImageView!
  18. @IBOutlet weak var newBlankPageLabel: NSTextField!
  19. @IBOutlet weak var newBlankPageImageView: NSImageView!
  20. @IBOutlet weak var importFromScannerLabel: NSTextField!
  21. @IBOutlet weak var importFromScannerImageView: NSImageView!
  22. var deviceBrowserWC: KMDeviceBrowserWindowController?
  23. @IBOutlet weak var leftBox: NSBox!
  24. @IBOutlet weak var rightBox: NSBox!
  25. @IBOutlet weak var leftBoxRightConstraint: NSLayoutConstraint!
  26. @IBOutlet weak var rightBoxLeftConstraint: NSLayoutConstraint!
  27. @IBOutlet weak var rightBoxTopConstraint: NSLayoutConstraint!
  28. @IBOutlet weak var rightBoxHeightConstraint: NSLayoutConstraint!
  29. override func viewDidLoad() {
  30. super.viewDidLoad()
  31. // Do view setup here.
  32. self.initLocalization()
  33. self.initializeUI()
  34. }
  35. // MARK: initialize
  36. func initializeUI() -> Void {
  37. self.openPDFFilesLabel.textColor = NSColor.km_init(hex: "#252629")
  38. self.openPDFFilesLabel.font = NSFont.SFProTextSemiboldFont(20.0)
  39. self.openPDFFilesImageView.image = NSImage(named: "icon_empty_addFiles")
  40. self.selectYourFilesBox.cornerRadius = 4.0
  41. self.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#1770F4")
  42. self.selectYourFilesLabel.textColor = NSColor.km_init(hex: "#FFFFFF")
  43. self.selectYourFilesLabel.font = NSFont.SFProTextRegularFont(16.0)
  44. self.selectYourFilesImageView.image = NSImage(named: "icon_SelectYourFiles")
  45. self.orDropFilesHereToOpenLabel.textColor = NSColor.km_init(hex: "#616469")
  46. self.orDropFilesHereToOpenLabel.font = NSFont.SFProTextRegularFont(14.0)
  47. self.creatPDFLabel.textColor = NSColor.km_init(hex: "#252629")
  48. self.creatPDFLabel.font = NSFont.SFProTextSemiboldFont(20.0)
  49. self.newFromFilesLabel.textColor = NSColor.km_init(hex: "#252629")
  50. self.newFromFilesLabel.font = NSFont.SFProTextRegularFont(16.0)
  51. self.newFromFilesImageView.image = NSImage(named: "icon_empty_NewFromFiles")
  52. self.newBlankPageLabel.textColor = NSColor.km_init(hex: "#252629")
  53. self.newBlankPageLabel.font = NSFont.SFProTextRegularFont(16.0)
  54. self.newBlankPageImageView.image = NSImage(named: "icon_empty_NewBlackPage")
  55. self.importFromScannerLabel.textColor = NSColor.km_init(hex: "#252629")
  56. self.importFromScannerLabel.font = NSFont.SFProTextRegularFont(16.0)
  57. self.importFromScannerImageView.image = NSImage(named: "icon_empty_ImportFromScanner")
  58. self.selectYourFilesBox.moveCallback = { [weak self](mouseEntered: Bool, mouseBox: KMBox) -> Void in
  59. if mouseEntered {
  60. self?.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#3F8FF6")
  61. } else {
  62. self?.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#1770F4")
  63. }
  64. }
  65. self.selectYourFilesBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in
  66. if downEntered {
  67. self?.openPDFButtonAction()
  68. }
  69. }
  70. }
  71. func initLocalization() -> Void {
  72. self.openPDFFilesLabel.stringValue = NSLocalizedString("Open PDF Files", comment: "")
  73. self.selectYourFilesLabel.stringValue = NSLocalizedString("Select Your Files", comment: "")
  74. self.orDropFilesHereToOpenLabel.stringValue = NSLocalizedString("or drop files here to open", comment: "")
  75. self.creatPDFLabel.stringValue = NSLocalizedString("Create PDF", comment: "")
  76. self.newFromFilesLabel.stringValue = NSLocalizedString("New From Files", comment: "")
  77. self.newBlankPageLabel.stringValue = NSLocalizedString("New Blank Page", comment: "")
  78. self.importFromScannerLabel.stringValue = NSLocalizedString("Import From Scanner", comment: "")
  79. }
  80. // MARK: Private Methods
  81. func imageToJPG(filePath: String, savePath: String) -> String {
  82. if NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "png" ||
  83. NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "PNG" {
  84. let imageName = NSString(string: NSString(string: filePath).lastPathComponent).deletingPathExtension
  85. let jpgPath = self.fetchDifferentFilePath(filePath: savePath + "/" + imageName + ".jpg")
  86. if (!FileManager.default.fileExists(atPath: jpgPath as String)) {
  87. FileManager.default.createFile(atPath: jpgPath as String, contents: nil)
  88. }
  89. // 加载 PNG 图像
  90. guard let pngImage = NSImage(contentsOfFile: filePath) else {
  91. KMPrint("Failed to load PNG image")
  92. return filePath
  93. }
  94. // 创建 NSBitmapImageRep 对象,并将 PNG 图像绘制到其中
  95. let bitmap = NSBitmapImageRep(data: pngImage.tiffRepresentation!)
  96. let rect = NSRect(origin: .zero, size: bitmap!.size)
  97. bitmap?.draw(in: rect)
  98. // 将 PNG 图像数据转换为 JPG 图像数据
  99. guard let jpgData = bitmap?.representation(using: .jpeg, properties: [:]) else {
  100. KMPrint("Failed to convert PNG to JPG")
  101. return filePath
  102. }
  103. // 保存 JPG 图像数据到文件
  104. let fileURL = URL(fileURLWithPath: jpgPath)
  105. do {
  106. try jpgData.write(to: fileURL)
  107. KMPrint("JPG image saved successfully")
  108. return fileURL.path
  109. } catch {
  110. KMPrint("Failed to save JPG image: \(error.localizedDescription)")
  111. return filePath
  112. }
  113. }
  114. return filePath
  115. }
  116. func openImageFile(url: URL) -> Void {
  117. let filePath = url.path
  118. let fileName: NSString = url.lastPathComponent as NSString
  119. let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String).deletingLastPathComponent
  120. let imageName = NSString(string: NSString(string: filePath).lastPathComponent).deletingPathExtension
  121. let path = self.fetchDifferentFilePath(filePath: savePath + "/" + imageName + ".pdf")
  122. if (!FileManager.default.fileExists(atPath: path.deletingLastPathComponent as String)) {
  123. try?FileManager.default.createDirectory(atPath: path.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil)
  124. }
  125. if (!FileManager.default.fileExists(atPath: path as String)) {
  126. FileManager.default.createFile(atPath: path as String, contents: nil)
  127. }
  128. let document = CPDFDocument.init()
  129. var success = false
  130. let jpgPath = self.imageToJPG(filePath: filePath, savePath: savePath)
  131. //FIXME: 无法插入图片
  132. let image = NSImage(contentsOfFile: jpgPath)
  133. let insertPageSuccess = document?.insertPage(image!.size, withImage: jpgPath, at: document!.pageCount)
  134. if insertPageSuccess != nil {
  135. //信号量控制异步
  136. let semaphore = DispatchSemaphore(value: 0)
  137. DispatchQueue.global().async {
  138. success = ((document?.write(toFile: path)) != nil)
  139. semaphore.signal()
  140. }
  141. semaphore.wait()
  142. } else {
  143. }
  144. if success {
  145. if !path.isPDFValid() {
  146. let alert = NSAlert()
  147. alert.alertStyle = .critical
  148. alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  149. alert.runModal()
  150. return
  151. }
  152. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: path), display: true) { document, documentWasAlreadyOpen, error in
  153. if error != nil {
  154. NSApp.presentError(error!)
  155. return
  156. }
  157. }
  158. }
  159. }
  160. func openOfficeFile(url: URL) -> Void {
  161. let filePath = url.path
  162. let folderPath = "convertToPDF.pdf"
  163. let savePath = folderPath.kUrlToPDFFolderPath()
  164. if (!FileManager.default.fileExists(atPath: savePath.deletingLastPathComponent as String)) {
  165. try?FileManager.default.createDirectory(atPath: savePath.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil)
  166. }
  167. if (!FileManager.default.fileExists(atPath: savePath as String)) {
  168. FileManager.default.createFile(atPath: savePath as String, contents: nil)
  169. }
  170. if savePath == nil {
  171. return
  172. }
  173. KMConvertPDFManager.convertFile(filePath, savePath: savePath as String) { success, errorDic in
  174. if errorDic != nil || !success || !FileManager.default.fileExists(atPath: savePath as String) {
  175. if FileManager.default.fileExists(atPath: savePath as String) {
  176. try?FileManager.default.removeItem(atPath: savePath as String)
  177. }
  178. let alert = NSAlert.init()
  179. alert.alertStyle = .critical
  180. var infoString = ""
  181. if errorDic != nil {
  182. for key in (errorDic! as Dictionary).keys {
  183. infoString = infoString.appendingFormat("%@\n", errorDic![key] as! CVarArg)
  184. }
  185. }
  186. alert.informativeText = NSLocalizedString("Please install Microsoft Office to create PDFs from Office files", comment: "")
  187. alert.messageText = NSLocalizedString("Failed to Create PDF", comment: "")
  188. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  189. alert.runModal()
  190. return
  191. }
  192. if !(savePath as String).isPDFValid() {
  193. let alert = NSAlert()
  194. alert.alertStyle = .critical
  195. alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  196. alert.runModal()
  197. return
  198. }
  199. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath as String), display: true) { document, documentWasAlreadyOpen, error in
  200. if error != nil {
  201. NSApp.presentError(error!)
  202. return
  203. }
  204. }
  205. }
  206. }
  207. func fetchUniquePath(_ originalPath: String) -> String {
  208. var path = originalPath
  209. let dManager = FileManager.default
  210. if !dManager.fileExists(atPath: path) {
  211. if path.extension.count < 1 {
  212. path = path.stringByAppendingPathExtension("pdf")
  213. }
  214. return path
  215. } else {
  216. let originalFullFileName = path.lastPathComponent
  217. let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent
  218. let originalExtension = path.extension
  219. let startIndex: Int = 0
  220. let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1
  221. let fileLocatePath = originalPath.substring(to: endIndex)
  222. var i = 1
  223. while (1 != 0) {
  224. var newName = String(format: "%@%ld", originalFileName, i)
  225. newName = String(format: "%@%@", newName, originalExtension)
  226. let newPath = fileLocatePath.stringByAppendingPathComponent(newName)
  227. if !dManager.fileExists(atPath: newPath) {
  228. return newPath
  229. } else {
  230. i+=1
  231. continue
  232. }
  233. }
  234. }
  235. }
  236. func fetchDifferentFilePath(filePath: String) -> String {
  237. var resultFilePath = filePath
  238. var index: Int = 0
  239. while (FileManager.default.fileExists(atPath: resultFilePath)) {
  240. index += 1
  241. let path = NSString(string: filePath).deletingPathExtension + "(" + String(index) + ")"
  242. resultFilePath = NSString(string: path).appendingPathExtension(NSString(string: filePath).pathExtension)!
  243. }
  244. return resultFilePath;
  245. }
  246. func openFile(withFilePath path: URL) -> Void {
  247. let type = path.pathExtension.lowercased()
  248. if (type == "pdf") {
  249. if !path.path.isPDFValid() {
  250. let alert = NSAlert()
  251. alert.alertStyle = .critical
  252. alert.messageText = NSLocalizedString("This file format is not supported, please drag in PDF, picture, Office format files", comment: "")
  253. alert.runModal()
  254. return
  255. }
  256. NSDocumentController.shared.openDocument(withContentsOf: path, display: true) { document, documentWasAlreadyOpen, error in
  257. if error != nil {
  258. NSApp.presentError(error!)
  259. return
  260. }
  261. }
  262. } else if (type == "jpg") ||
  263. (type == "cur") ||
  264. (type == "bmp") ||
  265. (type == "jpeg") ||
  266. (type == "gif") ||
  267. (type == "png") ||
  268. (type == "tiff") ||
  269. (type == "tif") ||
  270. (type == "ico") ||
  271. (type == "icns") ||
  272. (type == "tga") ||
  273. (type == "psd") ||
  274. (type == "eps") ||
  275. (type == "hdr") ||
  276. (type == "jp2") ||
  277. (type == "jpc") ||
  278. (type == "pict") ||
  279. (type == "sgi") ||
  280. (type == "heic") {
  281. openImageFile(url: path)
  282. } else if (type == "doc") ||
  283. (type == "docx") ||
  284. (type == "xls") ||
  285. (type == "xlsx") ||
  286. (type == "ppt") ||
  287. (type == "pptx") ||
  288. (type == "pptx") {
  289. let fileName: NSString = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: "")) as NSString
  290. let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String)
  291. openOfficeFile(url: path)
  292. }
  293. }
  294. func refreshLayout(isLimit limit: Bool) -> Void {
  295. if limit {
  296. if self.rightBoxTopConstraint != nil {
  297. self.rightBoxTopConstraint.constant = 348 + 40
  298. }
  299. if self.leftBoxRightConstraint != nil {
  300. self.leftBoxRightConstraint.constant = 32
  301. }
  302. if self.rightBoxLeftConstraint != nil {
  303. self.rightBoxLeftConstraint.constant = 32
  304. }
  305. if self.rightBoxHeightConstraint != nil {
  306. self.rightBoxHeightConstraint.constant = leftBox.frame.width
  307. }
  308. } else {
  309. if self.rightBoxTopConstraint != nil {
  310. self.rightBoxTopConstraint.constant = 40
  311. }
  312. if self.leftBoxRightConstraint != nil {
  313. self.leftBoxRightConstraint.constant = 380
  314. }
  315. if self.rightBoxLeftConstraint != nil {
  316. self.rightBoxLeftConstraint.constant = 32 + leftBox.frame.width + 20
  317. }
  318. if self.rightBoxHeightConstraint != nil {
  319. self.rightBoxHeightConstraint.constant = 328
  320. }
  321. }
  322. }
  323. // MARK: Action
  324. @IBAction func createPDFAction(_ sender: NSButton) {
  325. let tag = sender.tag;
  326. if tag == 0 {
  327. // New From Files
  328. self.trackEvent_create(eventName: "New From File")
  329. self.openSupportPDFButtonAction()
  330. } else if tag == 1 {
  331. // New Blank Page
  332. self.trackEvent_create(eventName: "New Blank Page")
  333. self.openBlankPage("")
  334. } else if tag == 2 {
  335. // Import From Scanner
  336. self.trackEvent_create(eventName: "Import From Scanner")
  337. self.importFromScanner("")
  338. }
  339. }
  340. func openPDFButtonAction() {
  341. NSOpenPanel.km_open_pdf_multi_success(self.view.window!, panel: nil) { urls in
  342. for url in urls {
  343. if !url.path.isPDFValid() {
  344. let alert = NSAlert()
  345. alert.alertStyle = .critical
  346. alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  347. alert.runModal()
  348. } else {
  349. NSDocumentController.shared.openDocument(withContentsOf: url, display: true) { document, documentWasAlreadyOpen, error in
  350. if error != nil {
  351. NSApp.presentError(error!)
  352. } else {
  353. }
  354. }
  355. }
  356. }
  357. }
  358. }
  359. func openSupportPDFButtonAction() {
  360. var window = self.view.window
  361. if (window == nil) {
  362. window = NSApp.mainWindow
  363. }
  364. NSPanel.km_open_multi_success(window!) { panel in
  365. var array: [String] = []
  366. for fileType in KMConvertPDFManager.supportFileType() {
  367. if let string = fileType as? String {
  368. array.append(string)
  369. }
  370. }
  371. panel.allowedFileTypes = KMTools.pdfExtensions + array
  372. } completion: { urls in
  373. for url in urls {
  374. let type = url.pathExtension.lowercased()
  375. if (type == "pdf" || type == "PDF") {
  376. NSDocumentController.shared.km_safe_openDocument(withContentsOf: url, display: true) { _, _, _ in
  377. }
  378. } else if (type == "jpg") ||
  379. (type == "cur") ||
  380. (type == "bmp") ||
  381. (type == "jpeg") ||
  382. (type == "gif") ||
  383. (type == "png") ||
  384. (type == "tiff") ||
  385. (type == "tif") ||
  386. (type == "ico") ||
  387. (type == "icns") ||
  388. (type == "tga") ||
  389. (type == "psd") ||
  390. (type == "eps") ||
  391. (type == "hdr") ||
  392. (type == "jp2") ||
  393. (type == "jpc") ||
  394. (type == "pict") ||
  395. (type == "sgi") ||
  396. (type == "heic") {
  397. self.openImageFile(url: url)
  398. } else if (type == "doc") ||
  399. (type == "docx") ||
  400. (type == "xls") ||
  401. (type == "xlsx") ||
  402. (type == "ppt") ||
  403. (type == "pptx") ||
  404. (type == "pptx") {
  405. self.openOfficeFile(url: url)
  406. }
  407. }
  408. }
  409. }
  410. @IBAction func openBlankPage(_ sender: Any) {
  411. let fileName: NSString = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: "")) as NSString
  412. let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String)
  413. if (!FileManager.default.fileExists(atPath: savePath.deletingLastPathComponent as String)) {
  414. try?FileManager.default.createDirectory(atPath: savePath.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil)
  415. }
  416. if (!FileManager.default.fileExists(atPath: savePath as String)) {
  417. FileManager.default.createFile(atPath: savePath as String, contents: nil)
  418. }
  419. let pdfDocument = CPDFDocument()
  420. pdfDocument?.insertPage(CGSize(width: 595, height: 842), at: 0)
  421. pdfDocument?.write(to: URL(fileURLWithPath: savePath))
  422. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath), display: true) { document, documentWasAlreadyOpen, error in
  423. if error != nil {
  424. NSApp.presentError(error!)
  425. } else {
  426. if document is KMMainDocument {
  427. let newDocument = document
  428. (newDocument as! KMMainDocument).isNewCreated = true
  429. }
  430. }
  431. }
  432. }
  433. @IBAction func importFromScanner(_ sender: Any) {
  434. deviceBrowserWC = KMDeviceBrowserWindowController.shared
  435. deviceBrowserWC!.type = .scanner
  436. deviceBrowserWC!.importScannerFileCallback = { [weak self](url: NSURL) -> Void in
  437. self?.openFile(withFilePath: url as URL)
  438. }
  439. deviceBrowserWC!.showWindow(NSApp.mainWindow)
  440. }
  441. }
  442. // MARK: - Analytics (埋点)
  443. extension KMAIOpenPDFFilesVC {
  444. func trackEvent_create(eventName: String) -> Void {
  445. KMAnalytics.trackEvent(eventName: eventName, parameters: [
  446. KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.home,
  447. KMAnalytics.Parameter.labelKey : KMAnalytics.Label.create_Btn], platform: .AppCenter, appTarget: .all)
  448. }
  449. }