// // KMBrowserWindowController+CreateFile.swift // PDF Reader Pro // // Created by Niehaoyu on 2025/1/17. // import Foundation // MARK: - 幻灯片 extension KMBrowserWindowController { func newFromFile() { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = KMImageToPDFMethod.supportedImageTypes() //MARK: 允许多选还是单选,如果是付费用户允许多选 openPanel.allowsMultipleSelection = true openPanel.message = KMLocalizedString("Select images to create a new document. To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.") if IAPProductsManager.default().isAvailableAllFunction(){ openPanel.allowsMultipleSelection = true } else { openPanel.allowsMultipleSelection = false } openPanel.beginSheetModal(for: NSWindow.currentWindow()) {[weak self] result in if result == NSApplication.ModalResponse.OK { guard let weakSelf = self else { return } let urls = openPanel.urls as [URL] self?.showBatchWindow(type: .imageToPDF, files: urls) } } } func newBlankPage() { let panel = NSSavePanel() panel.allowedFileTypes = ["pdf"] let resp = panel.runModal() if resp != .OK { return } let saveUrl = panel.url! let pdfDocument = CPDFDocument() pdfDocument?.insertPage(CGSize(width: 595, height: 842), at: 0) pdfDocument?.write(toFile: saveUrl.path) self.openFile(withFilePath: saveUrl) } func newFromWebPage() { createWC.own_beginSheetModal(for: self.window) {[weak self] string in guard let weakSelf = self else { return } if let path = string { self?.openFile(withFilePath: URL(fileURLWithPath: path)) } } } func newFromClipboard() { var error: NSError? let pboard = NSPasteboard.general var document = openDocumentWithImageFromPasteboard(pboard, error: &error) if document == nil{ document = openDocument(withURLFromPasteboard: pboard, showNotes: false, error: &error) } } func importFromScanner() { let vc = KMDeviceBrowserWindowController.shared vc.type = .scanner vc.importScannerFileCallback = { [weak self] (url: NSURL) -> Void in self?.openFile(withFilePath: url as URL) } vc.showWindow(nil) vc.window?.center() } //MARK: Batch func showBatchWindow(type: KMBatchCollectionViewType, subType: Int = 0, files: [URL]?) { let batchWindowController = KMBatchWindowController.init(windowNibName: "KMBatchWindowController") batchWindowController.window?.makeKeyAndOrderFront("") // var datas: [KMBatchProcessingTableViewModel] = [] // for file in files! { // let data = KMBatchProcessingTableViewModel.initWithFilePath(url: file) // datas.append(data) // } batchWindowController.inputData = files ?? [] batchWindowController.type = type batchWindowController.inputSubType = subType } func openFile(withFilePath path: URL) -> Void { let type = path.pathExtension.lowercased() if (type == "pdf") { self.openHistoryFilePath(url: path) } 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 openHistoryFilePath(url: URL) -> Void { 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.beginSheetModal(for: NSApp.mainWindow!) { [weak self] result in } return } if url.pathExtension.lowercased() == "pdf" { let pdfDoc = CPDFDocument.init(url: url) if pdfDoc != nil { let document = NSDocumentController.shared.document(for: url) var alreadyOpen = false for openDocument in NSDocumentController.shared.documents { if document == openDocument { alreadyOpen = true } } if !alreadyOpen { if self.browser?.tabCount() ?? 0 > 1{ if !IAPProductsManager.default().isAvailableAllFunction() { showLimitWindowAlert(url: url) return }else { } } } KMMainDocument().tryToUnlockDocument(pdfDoc!) var selectDocument: KMMainDocument? = nil if ((document?.isKind(of: KMMainDocument.self)) != nil) { selectDocument = (document as! KMMainDocument) } if selectDocument != nil { if selectDocument?.browser != nil { let currentIndex = selectDocument?.browser.tabStripModel.index(of: selectDocument) ?? 0 selectDocument?.browser.tabStripModel.selectTabContents(at: Int32(currentIndex), userGesture: true) let isVisible: Bool = selectDocument?.browser.window.isVisible ?? false let isMiniaturized: Bool = selectDocument?.browser.window.isMiniaturized ?? false if isVisible { selectDocument?.browser.window.orderFront(nil) } else if isMiniaturized { selectDocument?.browser.window.orderFront(nil) } } } else { NSDocumentController.shared.km_safe_openDocument(withContentsOf: url, display: true) { _, _, _ in } } } else { 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.beginSheetModal(for: NSApp.mainWindow!) { [weak self] result in } } } else { NSWorkspace.shared.open(url) } } func openImageFile(url: URL) -> Void { var 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 if NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "png" || NSString(string: NSString(string: filePath).lastPathComponent).pathExtension == "PNG" { 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 } // 创建 NSBitmapImageRep 对象,并将 PNG 图像绘制到其中 let bitmap = NSBitmapImageRep(data: pngImage.tiffRepresentation!) guard let bitmap = bitmap else { return } 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 } // 保存 JPG 图像数据到文件 let fileURL = URL(fileURLWithPath: jpgPath) do { try jpgData.write(to: fileURL) filePath = fileURL.path KMPrint("JPG image saved successfully") } catch { KMPrint("Failed to save JPG image: \(error.localizedDescription)") } } let image = NSImage(contentsOfFile: filePath) let insertPageSuccess = document?.insertPage(image!.size, withImage: filePath, 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 { NSDocumentController.shared.km_safe_openDocument(withContentsOf: URL(fileURLWithPath: path), display: true) { document, isOpened, error in if error != nil { NSApp.presentError(error!) } else { if FileManager.default.fileExists(atPath: filePath) { try? FileManager.default.removeItem(atPath: filePath) } if document is KMMainDocument { let newDocument = document (newDocument as! KMMainDocument).isNewCreated = true } } } } } func openOfficeFile(url: URL) -> Void { let filePath = url.path let folderPath = "convertToPDF.pdf" let savePath: String? = folderPath.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) } if savePath == nil { return } KMConvertPDFManager.convertFile(filePath, savePath: savePath!) { success, errorDic in if errorDic != nil || !success || !FileManager.default.fileExists(atPath: savePath!) { if FileManager.default.fileExists(atPath: savePath!) { try?FileManager.default.removeItem(atPath: savePath!) } 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 } NSDocumentController.shared.km_safe_openDocument(withContentsOf: URL(fileURLWithPath: savePath!), display: true) { _, _, _ in } } } func openImageToPdfWindow(urls: Array) { self.showBatchWindow(type: .imageToPDF, files: urls) } func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: AutoreleasingUnsafeMutablePointer?) -> Any? { var document: CPDFDocument? = nil var data: Data? = nil if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) { // pboard.types data = pboard.data(forType: NSPasteboard.PasteboardType.pdf) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.postScript.rawValue]) { // pboard.types data = pboard.data(forType: NSPasteboard.PasteboardType.postScript) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) { // pboard.types data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff) ?? Data()) } else { let images = pboard.readObjects(forClasses: [NSImage.self], options: [:]) let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:]) if images?.count ?? 0 > 0 { data = convertTIFFDataToPDF((images![0] as AnyObject).tiffRepresentation!) } else if strings?.count ?? 0 > 0 { data = KMOCTool.convertStringsToPDF(withString: strings ?? [""]) // convertStringsToPDF(strings!) } } if let data = data { _ = NSDocumentController.shared document = CPDFDocument(data: data) let fileName: NSString = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: "")) as NSString let savePath = fetchUniquePath(fileName.kUrlToPDFFolderPath() as String) let filePath = savePath.deletingLastPathComponent if FileManager.default.fileExists(atPath: filePath) == false { try?FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: false) } document?.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 } } } } else if let outError = outError { outError.pointee = NSError(domain: "SKDocumentErrorDomain", code: 3, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Unable to load data from clipboard", comment: "Error description")]) } return document } func openDocument(withURLFromPasteboard pboard: NSPasteboard, showNotes: Bool, error outError: inout NSError?) -> Any? { let theURLs = NSURL.readURLs(from: pboard) let url = theURLs?.count ?? 0 > 0 ? theURLs?[0] : nil let theURL: NSURL? = url as? NSURL let documentC = NSDocumentController.shared var document: NSDocument? = nil if (theURL as AnyObject).isFileURL == true { var _: NSError? = nil let type = try? documentC.typeForContents(of: theURL as! URL)//ForContents(ofURL: theURL, error: &error) if showNotes == false || NSDocument.readableTypes.contains(type ?? "") { documentC.openDocument(withContentsOf: theURL as! URL, display: true, completionHandler: { resultDocument, success, err in document = resultDocument }) } else if NSDocument.readableTypes.contains(type ?? "") { for doc in documentC.documents { let sel = NSSelectorFromString("sourceFileURL") if doc.responds(to: sel) && doc.fileURL == theURL as? URL { document = doc break } } if let document: NSDocument = document { document.showWindows() } else { if let document = try? documentC.makeUntitledDocument(ofType: KMNotesDocumentType) { document.fileURL = URL(fileURLWithPath: theURL?.path ?? "") documentC.addDocument(document) document.makeWindowControllers() document.showWindows() } } } } return document } func showLimitWindowAlert(url: URL?) { if !KMDataManager.default.isTabbingWin{ KMDataManager.default.isTabbingWin = true let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController() tabbingWin.selectCallBack = {[weak self] continueOrNot in KMDataManager.default.isTabbingWin = false if continueOrNot { self?.reopenDocument(forPaths: url?.path) } else { } } self.km_beginSheet(windowC: tabbingWin) } } 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 isDamageImage(image: NSImage?, path: String) -> Bool { if (image == nil) { return true } let addImageAnnotation = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).last!.appendingPathComponent(Bundle.main.bundleIdentifier!).appendingPathComponent("addImageAnnotation") if !FileManager.default.fileExists(atPath: addImageAnnotation.path) { try? FileManager.default.createDirectory(atPath: addImageAnnotation.path, withIntermediateDirectories: false, attributes: nil) } guard let data = image!.tiffRepresentation else { return false } guard let imageRep = NSBitmapImageRep(data: data) else { return false } imageRep.size = image!.size var imageData: Data? if path.lowercased() == "png" { imageData = imageRep.representation(using: .png, properties: [:]) } else { imageData = imageRep.representation(using: .jpeg, properties: [:]) } let rPath: URL = addImageAnnotation.appendingPathComponent(tagString()).appendingPathExtension("png") if let data = imageData { try?data.write(to: rPath) return false } else { return true } } func tagString() -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyMMddHHmmss" let currentDate = Date() let randomNum = Int(arc4random_uniform(10000)) let str = String(format: "%@%04d", dateFormatter.string(from: Date()),randomNum) return str } func convertTIFFDataToPDF(_ tiffData: Data) -> Data? { guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil } let pdfData = NSMutableData(capacity: tiffData.count) let consumer = CGDataConsumer(data: pdfData! as CFMutableData)! var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height)) let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil) ctxt!.beginPDFPage(nil) ctxt!.draw(cgImage, in: rect) ctxt!.endPDFPage() ctxt!.closePDF() return pdfData as? Data } func createBaseFoldPath() -> String { let folderPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last?.appending("/\(Bundle.main.bundleIdentifier!)") if (FileManager.default.fileExists(atPath: folderPath!) == false) { try?FileManager.default.createDirectory(atPath: folderPath!, withIntermediateDirectories: false) } return folderPath ?? "" } func filePathCheck(path: String) -> String { var i: Int = 0 let fileURL = URL(fileURLWithPath: path) var newPath: String = path let fileManager = FileManager.default while fileManager.fileExists(atPath: newPath) { i += 1 newPath = fileURL.deletingPathExtension().path newPath.append("(\(i))") newPath.append(".") newPath.append(fileURL.pathExtension) } return newPath } func screenShot_SelectArea(_ sender: Any?) { KMScreenShotHandler.beginScreenshot_SelectRectWithCompleteHandler { ima in if let image = ima { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let folderPath = self.createBaseFoldPath() let savePathOld = folderPath + "/screenShot.pdf" var savePath = self.filePathCheck(path: savePathOld) let newDocument = CPDFDocument() _ = newDocument?.km_insert(imageData: image.jpgData() ?? Data(), pageSize: image.size, at: newDocument?.pageCount ?? 0) let writeSuccess = newDocument?.write(to: URL(fileURLWithPath: savePath)) if writeSuccess ?? false { if self.checkOpenNewDocument(path: savePath) { self.savePdf(savePath) } } else { } } } } } func screenShot_Window(_ sender: Any?) { KMPrint("screenShot_Window") KMScreenShotHandler.beginScreenShot_SelectWindowCompleteHandler { ima in if let image = ima { if image.size.equalTo(.zero) == true { } else { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let folderPath = self.createBaseFoldPath() let savePathOld = folderPath + "/screenShot.pdf" var savePath = self.filePathCheck(path: savePathOld) let newDocument = CPDFDocument() _ = newDocument?.km_insert(imageData: image.jpgData() ?? Data(), pageSize: image.size, at: newDocument?.pageCount ?? 0) let writeSuccess = newDocument?.write(to: URL(fileURLWithPath: savePath)) if writeSuccess == true { if self.checkOpenNewDocument(path: savePath) { self.savePdf(savePath) } // try? FileManager.default.removeItem(atPath: savePath) } else { } } } } } } func screenShot_FullScreenDelay(_ sender: Any?) {//不延迟 KMPrint("screenShot_FullScreenDelay") KMScreenShotHandler.beginScreenShot_FullSreenWithDelayTime(0) { ima in if let image = ima { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let folderPath = self.createBaseFoldPath() let savePathOld = folderPath + "/screenShot.pdf" var savePath = self.filePathCheck(path: savePathOld) let newDocument = CPDFDocument() _ = newDocument?.km_insert(imageData: image.jpgData() ?? Data(), pageSize: image.size, at: newDocument?.pageCount ?? 0) let writeSuccess = newDocument?.write(to: URL(fileURLWithPath: savePath)) if writeSuccess == true { if self.checkOpenNewDocument(path: savePath) { self.savePdf(savePath) } // try? FileManager.default.removeItem(atPath: savePath) } else { } } } } } func screenShot_FullScreen(_ sender: Any?) {//延迟3秒 KMPrint("screenShot_FullScreen") KMScreenShotHandler.beginScreenShot_FullSreenWithDelayTime(3) { ima in if let image = ima { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { let folderPath = self.createBaseFoldPath() let savePathOld = folderPath + "/screenShot.pdf" var savePath = self.filePathCheck(path: savePathOld) let newDocument = CPDFDocument() _ = newDocument?.km_insert(imageData: image.jpgData() ?? Data(), pageSize: image.size, at: newDocument?.pageCount ?? 0) let writeSuccess = newDocument?.write(to: URL(fileURLWithPath: savePath)) if writeSuccess == true { self.savePdf(savePath) // try? FileManager.default.removeItem(atPath: savePath) } else { } } } } } func checkOpenNewDocument(path: String) -> Bool { let tabCount = self.km_browser?.tabCount() ?? 0 if tabCount > 1{ if !IAPProductsManager.default().isAvailableAllFunction() { let preferenceNoteShow = UserDefaults.standard.bool(forKey: KMTabbingHintShowFlag) if preferenceNoteShow { menuItemAction_newTagPageToNewWindow("") } else { if !KMDataManager.default.isTabbingWin{ KMDataManager.default.isTabbingWin = true let tabbingWin: KMTabbingHintWindowController = KMTabbingHintWindowController() tabbingWin.selectCallBack = {[weak self] continueOrNot in KMDataManager.default.isTabbingWin = false if continueOrNot { self?.reopenDocumentForNewWindow(savePath: path) } else { } } self.km_beginSheet(windowC: tabbingWin) } } return false }else { if KMPreference.shared.openDocumentType == .newWindow { self.reopenDocumentForNewWindow(savePath: path) return false } } } return true } func menuItemAction_newTagPageToNewWindow(_ sender: Any) { if (self.canResponseDocumentAction() == false) { return } self.openNewWindow(sender) } func reopenDocumentForNewWindow(savePath: String) { let browser = KMBrowser.init() as KMBrowser browser.windowController = KMBrowserWindowController.init(browser: browser) browser.addHomeTabContents() browser.windowController.showWindow(self) self.savePdf(savePath) } func savePdf(_ filePath: String) -> Void { let docVc = KMDocumentController.shared docVc.openDocument(withContentsOf: URL(fileURLWithPath: filePath), 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 } } } } }