// // KMAIOpenPDFFilesVC.swift // PDF Reader Pro // // Created by wanjun on 2023/5/22. // import Cocoa class KMAIOpenPDFFilesVC: NSViewController { @IBOutlet weak var openPDFFilesLabel: NSTextField! @IBOutlet weak var openPDFFilesImageView: NSImageView! @IBOutlet weak var selectYourFilesBox: KMBox! @IBOutlet weak var selectYourFilesLabel: NSTextField! @IBOutlet weak var selectYourFilesImageView: NSImageView! @IBOutlet weak var orDropFilesHereToOpenLabel: NSTextField! @IBOutlet weak var creatPDFLabel: NSTextField! @IBOutlet weak var newFromFilesLabel: NSTextField! @IBOutlet weak var newFromFilesImageView: NSImageView! @IBOutlet weak var newBlankPageLabel: NSTextField! @IBOutlet weak var newBlankPageImageView: NSImageView! @IBOutlet weak var importFromScannerLabel: NSTextField! @IBOutlet weak var importFromScannerImageView: NSImageView! var deviceBrowserWC: KMDeviceBrowserWindowController? @IBOutlet weak var leftBox: NSBox! @IBOutlet weak var rightBox: NSBox! @IBOutlet weak var leftBoxRightConstraint: NSLayoutConstraint! @IBOutlet weak var rightBoxLeftConstraint: NSLayoutConstraint! @IBOutlet weak var rightBoxTopConstraint: NSLayoutConstraint! @IBOutlet weak var rightBoxHeightConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() // Do view setup here. self.initLocalization() self.initializeUI() } // MARK: initialize func initializeUI() -> Void { self.openPDFFilesLabel.textColor = NSColor.km_init(hex: "#252629") self.openPDFFilesLabel.font = NSFont.SFProTextSemiboldFont(20.0) self.openPDFFilesImageView.image = NSImage(named: "icon_empty_addFiles") self.selectYourFilesBox.cornerRadius = 4.0 self.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#1770F4") self.selectYourFilesLabel.textColor = NSColor.km_init(hex: "#FFFFFF") self.selectYourFilesLabel.font = NSFont.SFProTextRegularFont(16.0) self.selectYourFilesImageView.image = NSImage(named: "icon_SelectYourFiles") self.orDropFilesHereToOpenLabel.textColor = NSColor.km_init(hex: "#616469") self.orDropFilesHereToOpenLabel.font = NSFont.SFProTextRegularFont(14.0) self.creatPDFLabel.textColor = NSColor.km_init(hex: "#252629") self.creatPDFLabel.font = NSFont.SFProTextSemiboldFont(20.0) self.newFromFilesLabel.textColor = NSColor.km_init(hex: "#252629") self.newFromFilesLabel.font = NSFont.SFProTextRegularFont(16.0) self.newFromFilesImageView.image = NSImage(named: "icon_empty_NewFromFiles") self.newBlankPageLabel.textColor = NSColor.km_init(hex: "#252629") self.newBlankPageLabel.font = NSFont.SFProTextRegularFont(16.0) self.newBlankPageImageView.image = NSImage(named: "icon_empty_NewBlackPage") self.importFromScannerLabel.textColor = NSColor.km_init(hex: "#252629") self.importFromScannerLabel.font = NSFont.SFProTextRegularFont(16.0) self.importFromScannerImageView.image = NSImage(named: "icon_empty_ImportFromScanner") self.selectYourFilesBox.moveCallback = { [weak self](mouseEntered: Bool, mouseBox: KMBox) -> Void in if mouseEntered { self?.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#3F8FF6") } else { self?.selectYourFilesBox.fillColor = NSColor.km_init(hex: "#1770F4") } } self.selectYourFilesBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in if downEntered { self?.openPDFButtonAction() } } } func initLocalization() -> Void { self.openPDFFilesLabel.stringValue = NSLocalizedString("Open PDF Files", comment: "") self.selectYourFilesLabel.stringValue = NSLocalizedString("Select Your Files", comment: "") self.orDropFilesHereToOpenLabel.stringValue = NSLocalizedString("or drop files here to open", comment: "") self.creatPDFLabel.stringValue = NSLocalizedString("Create PDF", comment: "") self.newFromFilesLabel.stringValue = NSLocalizedString("New From Files", comment: "") self.newBlankPageLabel.stringValue = NSLocalizedString("New Blank Page", comment: "") self.importFromScannerLabel.stringValue = NSLocalizedString("Import From Scanner", comment: "") } // MARK: Private Methods 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 } func openImageFile(url: URL) -> Void { let filePath = url.path let fileName: NSString = url.lastPathComponent as NSString let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String).deletingLastPathComponent let imageName = NSString(string: NSString(string: filePath).lastPathComponent).deletingPathExtension let path = self.fetchDifferentFilePath(filePath: savePath + "/" + imageName + ".pdf") if (!FileManager.default.fileExists(atPath: path.deletingLastPathComponent as String)) { try?FileManager.default.createDirectory(atPath: path.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil) } if (!FileManager.default.fileExists(atPath: path as String)) { FileManager.default.createFile(atPath: path as String, contents: nil) } let document = CPDFDocument.init() var success = false let jpgPath = self.imageToJPG(filePath: filePath, savePath: savePath) //FIXME: 无法插入图片 let image = NSImage(contentsOfFile: jpgPath) let insertPageSuccess = document?.insertPage(image!.size, withImage: jpgPath, at: document!.pageCount) if insertPageSuccess != nil { //信号量控制异步 let semaphore = DispatchSemaphore(value: 0) DispatchQueue.global().async { success = ((document?.write(toFile: path)) != nil) semaphore.signal() } semaphore.wait() } else { } if success { if !path.isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: path), display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) return } } } } func openOfficeFile(url: URL) -> Void { let filePath = url.path let folderPath = "convertToPDF.pdf" let savePath = folderPath.kUrlToPDFFolderPath() if (!FileManager.default.fileExists(atPath: savePath.deletingLastPathComponent as String)) { try?FileManager.default.createDirectory(atPath: savePath.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil) } if (!FileManager.default.fileExists(atPath: savePath as String)) { FileManager.default.createFile(atPath: savePath as String, contents: nil) } if savePath == nil { return } KMConvertPDFManager.convertFile(filePath, savePath: savePath as String) { success, errorDic in if errorDic != nil || !success || !FileManager.default.fileExists(atPath: savePath as String) { if FileManager.default.fileExists(atPath: savePath as String) { try?FileManager.default.removeItem(atPath: savePath as String) } let alert = NSAlert.init() alert.alertStyle = .critical var infoString = "" if errorDic != nil { for key in (errorDic! as Dictionary).keys { infoString = infoString.appendingFormat("%@\n", errorDic![key] as! CVarArg) } } alert.informativeText = NSLocalizedString("Please install Microsoft Office to create PDFs from Office files", comment: "") alert.messageText = NSLocalizedString("Failed to Create PDF", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() return } if !(savePath as String).isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath as String), display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) return } } } } func fetchUniquePath(_ originalPath: String) -> String { var path = originalPath let dManager = FileManager.default if !dManager.fileExists(atPath: path) { if path.extension.count < 1 { path = path.stringByAppendingPathExtension("pdf") } return path } else { let originalFullFileName = path.lastPathComponent let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent let originalExtension = path.extension let startIndex: Int = 0 let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1 let fileLocatePath = originalPath.substring(to: endIndex) var i = 1 while (1 != 0) { var newName = String(format: "%@%ld", originalFileName, i) newName = String(format: "%@%@", newName, originalExtension) let newPath = fileLocatePath.stringByAppendingPathComponent(newName) if !dManager.fileExists(atPath: newPath) { return newPath } else { i+=1 continue } } } } 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; } func openFile(withFilePath path: URL) -> Void { let type = path.pathExtension.lowercased() if (type == "pdf") { if !path.path.isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("This file format is not supported, please drag in PDF, picture, Office format files", comment: "") alert.runModal() return } NSDocumentController.shared.openDocument(withContentsOf: path, display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) return } } } else if (type == "jpg") || (type == "cur") || (type == "bmp") || (type == "jpeg") || (type == "gif") || (type == "png") || (type == "tiff") || (type == "tif") || (type == "ico") || (type == "icns") || (type == "tga") || (type == "psd") || (type == "eps") || (type == "hdr") || (type == "jp2") || (type == "jpc") || (type == "pict") || (type == "sgi") || (type == "heic") { openImageFile(url: path) } else if (type == "doc") || (type == "docx") || (type == "xls") || (type == "xlsx") || (type == "ppt") || (type == "pptx") || (type == "pptx") { let fileName: NSString = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: "")) as NSString let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String) openOfficeFile(url: path) } } func refreshLayout(isLimit limit: Bool) -> Void { if limit { if self.rightBoxTopConstraint != nil { self.rightBoxTopConstraint.constant = 348 + 40 } if self.leftBoxRightConstraint != nil { self.leftBoxRightConstraint.constant = 32 } if self.rightBoxLeftConstraint != nil { self.rightBoxLeftConstraint.constant = 32 } if self.rightBoxHeightConstraint != nil { self.rightBoxHeightConstraint.constant = leftBox.frame.width } } else { if self.rightBoxTopConstraint != nil { self.rightBoxTopConstraint.constant = 40 } if self.leftBoxRightConstraint != nil { self.leftBoxRightConstraint.constant = 380 } if self.rightBoxLeftConstraint != nil { self.rightBoxLeftConstraint.constant = 32 + leftBox.frame.width + 20 } if self.rightBoxHeightConstraint != nil { self.rightBoxHeightConstraint.constant = 328 } } } // MARK: Action @IBAction func createPDFAction(_ sender: NSButton) { let tag = sender.tag; if tag == 0 { // New From Files self.trackEvent_create(eventName: "New From File") self.openSupportPDFButtonAction() } else if tag == 1 { // New Blank Page self.trackEvent_create(eventName: "New Blank Page") self.openBlankPage("") } else if tag == 2 { // Import From Scanner self.trackEvent_create(eventName: "Import From Scanner") self.importFromScanner("") } } func openPDFButtonAction() { NSOpenPanel.km_open_pdf_multi_success(self.view.window!, panel: nil) { urls in for url in urls { if !url.path.isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() } else { NSDocumentController.shared.openDocument(withContentsOf: url, display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) } else { } } } } } } func openSupportPDFButtonAction() { var window = self.view.window if (window == nil) { window = NSApp.mainWindow } NSPanel.km_open_multi_success(window!) { panel in var array: [String] = [] for fileType in KMConvertPDFManager.supportFileType() { if let string = fileType as? String { array.append(string) } } panel.allowedFileTypes = KMTools.pdfExtensions + array } completion: { urls in for url in urls { let type = url.pathExtension.lowercased() if (type == "pdf" || type == "PDF") { NSDocumentController.shared.km_safe_openDocument(withContentsOf: url, display: true) { _, _, _ in } } else if (type == "jpg") || (type == "cur") || (type == "bmp") || (type == "jpeg") || (type == "gif") || (type == "png") || (type == "tiff") || (type == "tif") || (type == "ico") || (type == "icns") || (type == "tga") || (type == "psd") || (type == "eps") || (type == "hdr") || (type == "jp2") || (type == "jpc") || (type == "pict") || (type == "sgi") || (type == "heic") { self.openImageFile(url: url) } else if (type == "doc") || (type == "docx") || (type == "xls") || (type == "xlsx") || (type == "ppt") || (type == "pptx") || (type == "pptx") { self.openOfficeFile(url: url) } } } } @IBAction func openBlankPage(_ sender: Any) { let fileName: NSString = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: "")) as NSString let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String) if (!FileManager.default.fileExists(atPath: savePath.deletingLastPathComponent as String)) { try?FileManager.default.createDirectory(atPath: savePath.deletingLastPathComponent as String, withIntermediateDirectories: true, attributes: nil) } if (!FileManager.default.fileExists(atPath: savePath as String)) { FileManager.default.createFile(atPath: savePath as String, contents: nil) } let pdfDocument = CPDFDocument() pdfDocument?.insertPage(CGSize(width: 595, height: 842), at: 0) pdfDocument?.write(to: URL(fileURLWithPath: savePath)) NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath), display: true) { document, documentWasAlreadyOpen, error in if error != nil { NSApp.presentError(error!) } else { if document is KMMainDocument { let newDocument = document (newDocument as! KMMainDocument).isNewCreated = true } } } } @IBAction func importFromScanner(_ sender: Any) { deviceBrowserWC = KMDeviceBrowserWindowController.shared deviceBrowserWC!.type = .scanner deviceBrowserWC!.importScannerFileCallback = { [weak self](url: NSURL) -> Void in self?.openFile(withFilePath: url as URL) } deviceBrowserWC!.showWindow(NSApp.mainWindow) } } // MARK: - Analytics (埋点) extension KMAIOpenPDFFilesVC { func trackEvent_create(eventName: String) -> Void { KMAnalytics.trackEvent(eventName: eventName, parameters: [ KMAnalytics.Parameter.categoryKey : KMAnalytics.Category.home, KMAnalytics.Parameter.labelKey : KMAnalytics.Label.create_Btn], platform: .AppCenter, appTarget: .all) } }