// // KMMergeWindowController.swift // PDF Reader Pro // // Created by lizhe on 2023/11/8. // import Cocoa typealias KMMergeWindowControllerCancelAction = (_ controller: KMMergeWindowController) -> Void typealias KMMergeWindowControllerAddFilesAction = (_ controller: KMMergeWindowController) -> Void typealias KMMergeWindowControllerMergeAction = (_ controller: KMMergeWindowController, _ filePath: String) -> Void typealias KMMergeWindowControllerClearAction = (_ controller: KMMergeWindowController) -> Void class KMMergeWindowController: KMBaseWindowController { @IBOutlet weak var mergeView: KMMergeView! // var cancelAction: KMMergeWindowControllerCancelAction? var oldPDFDocument: PDFDocument = PDFDocument() var password: String = "" var oriDucumentUrl: URL? { didSet { oldPDFDocument = PDFDocument(url: oriDucumentUrl!)! oldPDFDocument.unlock(withPassword: self.password) } } var type: KMMergeViewType = .add var pageIndex: Int? var mergeAction: KMMergeWindowControllerMergeAction? // - (id)initWithPDFDocument:(PDFDocument *)document password:(NSString *)password // { // if (self = [super initWithWindowNibName:@"KMPDFEditAppendWindow"]) { // // // self.PDFDocument = document; // self.PDFDocument = [[PDFDocument alloc] init]; // self.editType = KMPDFPageEditAppend; // _lockFilePathArr = [[NSMutableArray alloc] init]; // _files = [[NSMutableArray alloc] init]; // // KMFileAttribute *file = [[KMFileAttribute alloc] init]; // file.myPDFDocument = document; // file.filePath = document.documentURL.path; // file.oriFilePath = self.oriDucumentUrl.path; // if (password && password.length > 0) { // file.password = password; // file.isLocked = YES; // } // [self.files addObject:file]; // } // return self; // } convenience init(document: PDFDocument, password: String) { self.init(windowNibName: "KMMergeWindowController") self.password = password } override func windowDidLoad() { super.windowDidLoad() self.window!.title = NSLocalizedString("Merge PDF Files", comment: ""); // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. self.mergeView.type = self.type mergeView.addFilesAction = { [weak self] view in guard let self = self else { return } self.addFile() } mergeView.clearAction = { view in } mergeView.mergeAction = { [weak self] view, files, size in guard let self = self else { return } self.mergeFiles(files: files, size: size) } mergeView.cancelAction = { [weak self] view in guard let self = self else { return } self._clearImageData() self.cancelAction?(self) } } } extension KMMergeWindowController { func addFile() { var size = 0.0 let files = self.mergeView.files for file in files { size = size + file.fileSize } if KMMemberInfo.shared.isMemberAllFunction == false && (files.count >= 2 || size > 20 * 1024 * 1024) { let winC = KMProductCompareWC.shared if self.kEventTag == 1 { winC.kEventName = "Onbrd_Merge_BuyNow" } else { winC.kEventName = "Reading_Merge_BuyNow" } KMMemberInfo.shared.advancedFunctionUsage() return } let openPanel = NSOpenPanel() // openPanel.allowedFileTypes = ["pdf"] openPanel.allowedFileTypes = KMTools.imageExtensions + KMTools.pdfExtensions if KMPurchaseManager.manager.state == .subscription { openPanel.allowsMultipleSelection = true openPanel.message = NSLocalizedString("Select files to merge. To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "") } else { openPanel.allowsMultipleSelection = false openPanel.message = NSLocalizedString("Select files to merge, only one file can be selected at a time.", comment: "") } openPanel.beginSheetModal(for: self.window!) { (result) in if result == NSApplication.ModalResponse.OK { var array: [URL] = [] for fileURL in openPanel.urls { if KMTools.isImageType(fileURL.pathExtension) { if let image = NSImage(contentsOf: fileURL) { if let page = PDFPage(image: image) { let document = PDFDocument() document.insert(page, at: 0) var path = self._saveImagePath() + "/" + fileURL.deletingPathExtension().lastPathComponent + ".pdf" path = KMTools.getUniqueFilePath(filePath: path) let result = document.write(toFile: path) if result { // array.append(URL(fileURLWithPath: path)) let file = KMFileAttribute() file.filePath = path file.oriFilePath = fileURL.path file.myPDFDocument = document let attribe = try?FileManager.default.attributesOfItem(atPath: fileURL.path) let fileSize = attribe?[FileAttributeKey.size] as? CGFloat ?? 0 size = fileSize + size if KMMemberInfo.shared.isMemberAllFunction == false && (files.count >= 2 || size > 20 * 1024 * 1024) { KMMemberInfo.shared.advancedFunctionUsage() return } self.mergeView.files.append(file) } } } else { Task { _ = await KMAlertTool.runModel(message: NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")) } } } else { array.append(fileURL) } } let attribe = try?FileManager.default.attributesOfItem(atPath: openPanel.urls.first!.path) let fileSize = attribe?[FileAttributeKey.size] as? CGFloat ?? 0 size = fileSize + size if KMMemberInfo.shared.isMemberAllFunction == false && (files.count >= 2 || size > 20 * 1024 * 1024) { KMMemberInfo.shared.advancedFunctionUsage() return } self.mergeView.addFilePaths(urls: array) } } } private func _saveImagePath() -> String { let rootPath = KMDataManager.fetchAppSupportOfBundleIdentifierDirectory() let path = rootPath.appendingPathComponent("Merge").path if FileManager.default.fileExists(atPath: path) == false { try?FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false) } return path } private func _clearImageData() { let path = self._saveImagePath() if FileManager.default.fileExists(atPath: path) { try?FileManager.default.removeItem(atPath: path) } } func mergeFiles(files: [KMFileAttribute], size: CGSize = .zero) { var size = 0.0 for file in files { size = size + file.fileSize } if KMMemberInfo.shared.isMemberAllFunction == false && (files.count >= 2 || size > 20 * 1024 * 1024) { KMMemberInfo.shared.advancedFunctionUsage() return } var filesCount = 1 if self.oriDucumentUrl != nil { filesCount = 0 } if files.count <= filesCount { let alert = NSAlert.init() alert.alertStyle = .critical alert.messageText = NSLocalizedString("To start merging, please select at least 2 files.", comment: "") alert.runModal() return } var rootPDFOutlineArray: [PDFOutline] = [] var allPage = true //只有是全部才支持大纲的合并 for file in files { if file.fetchSelectPages().count == 0 { let alert = NSAlert.init() alert.alertStyle = .critical alert.messageText = "\(file.filePath.lastPathComponent) + \(NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: ""))" alert.runModal() return } allPage = file.bAllPage /*防止文件被地址变换后crash*/ guard let tDocument = PDFDocument(url: NSURL(fileURLWithPath: file.filePath) as URL) else { print("文件不存在") let alert = NSAlert.init() alert.alertStyle = .critical alert.messageText = "\(file.filePath.lastPathComponent) + \(NSLocalizedString("Failed to merge!", comment: ""))" alert.runModal() return } var outlineArray: [PDFOutline] = [] // if file.isLocked { tDocument.unlock(withPassword: file.password) // } if tDocument.outlineRoot != nil { rootPDFOutlineArray.append((tDocument.outlineRoot)!) self.fetchAllOfChildren((tDocument.outlineRoot)!, containerArray: &outlineArray) outlineArray.removeObject((tDocument.outlineRoot)!) } else { let rootOutline = PDFOutline.init() tDocument.outlineRoot = rootOutline if tDocument.outlineRoot != nil { rootPDFOutlineArray.append(tDocument.outlineRoot!) } } for number in file.fetchSelectPages() { let page = tDocument.page(at: number - 1) // if pageIndex != nil { // self.oldPDFDocument.insert(page!, at: pageIndex!) // pageIndex = pageIndex! + 1 // } else { self.oldPDFDocument.insert(page!, at: self.oldPDFDocument.pageCount) // } // self.insertIndexSet.addIndex:(self.pdfDocument.pageCount - 1) } } var theFilepath = files.first?.filePath if let filepath = files.first?.oriFilePath { theFilepath = filepath } let fileName = (theFilepath?.deletingPathExtension.lastPathComponent ?? "") + "_Merged" DispatchQueue.main.async { if self.oldPDFDocument.outlineRoot == nil { self.oldPDFDocument.outlineRoot = PDFOutline.init() } // if allPage { var insertIndex = 0 for i in 0..