// // KMBatchSettingView.swift // PDF Master // // Created by lizhe on 2023/1/16. // import Cocoa class KMBatchSettingView: KMBaseXibView { var currentView: KMBatchSettingItemView = KMBatchSettingItemView() lazy var itemViewArray: [KMBatchSettingItemView] = [] var filesData: [KMBatchProcessingTableViewModel]? { didSet { currentView.filesData = filesData! } } var type: KMBatchCollectionViewType = .convertPDF { didSet { self.reloadData() } } var subType: Any? { didSet { self.reloadData() } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Drawing code here. } override func setup() { super.setup() self.contentView.wantsLayer = true self.contentView.layer?.backgroundColor = NSColor.km_init(hex: "#F7F8FA").cgColor self.type = .convertPDF } override func reloadData() { super.reloadData() if (self.type != self.currentView.type) { let view: KMBatchSettingItemView = self.fetchCurrentView(type: self.type, subType: self.subType as Any) self.currentView.removeFromSuperview() self.addSubview(view) view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ view.topAnchor.constraint(equalTo: topAnchor), view.leftAnchor.constraint(equalTo: leftAnchor), view.rightAnchor.constraint(equalTo: rightAnchor), view.bottomAnchor.constraint(equalTo: bottomAnchor)]) view.updateConstraintsForSubtreeIfNeeded() self.currentView = view } else if (self.subType.debugDescription != self.currentView.subType.debugDescription) { self.currentView.subType = self.subType } } func fetchCurrentView(type: KMBatchCollectionViewType, subType: Any) -> KMBatchSettingItemView { var resultView: KMBatchSettingItemView = KMBatchSecurityView.init() var isExist = false for item in self.itemViewArray { if item.type == type { isExist = true resultView = item } } if !isExist { switch type { case .convertPDF: resultView = KMBatchConvertPDFView.init() resultView.export = { [unowned self] (view, data) in self.convertPDFExport(data: data) } break case .compress: resultView = KMBatchCompressView.init() resultView.export = { [unowned self] (view, data) in self.compressExport(data: data) } break case .security: resultView = KMBatchSecurityView.init() resultView.export = { [unowned self] (view, data) in self.securityExport(data: data) } break case .watermark: resultView = KMBatchWatermarkView.init() resultView.export = { [unowned self] (view, data) in self.waterMarkApplay(data: data) } break case .background: resultView = KMBatchBackgroundView.init() resultView.export = { [unowned self] (view, data) in self.backgroundApplay(data: data) } break case .headerAndFooter: resultView = KMBatchHeaderAndFooterView.init() resultView.export = { [unowned self] (view, data) in self.headAndFooterApplay(data: data) } break case .batesNumber: resultView = KMBatchBatesNumberView.init() resultView.export = { [unowned self] (view, data) in self.batesApplay(data: data) } break case .batchRemove: resultView = KMBatchRemoveView.init() resultView.export = { [unowned self] (view, data) in self.removeApplay(data: data) } break default: KMPrint("找不到") break } resultView.type = type resultView.subType = subType resultView.filesData = self.filesData ?? [] self.itemViewArray.append(resultView) } else { if resultView.filesData.count == 0 && self.filesData?.count != 0{ resultView.filesData = self.filesData ?? [] } } return resultView } } protocol KMBatchSettingViewExport {} extension KMBatchSettingView: KMBatchSettingViewExport { //MARK: 转档 func convertPDFExport(data: KMBatchSettingItemViewModel) { let panel = NSOpenPanel() panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.convertFile(outputFolderPath: outputFolderPath!, data: data, filesData: self.filesData) } } func convertFile(outputFolderPath: String, data: KMBatchSettingItemViewModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { DispatchQueue.global().async { for item in filesData! { //创建Document let filePath = item.filePath let document = PDFDocument(url: URL(fileURLWithPath: filePath)) let convert = KMPDFConvert() let settingData = data as? KMBatchConvertPDFViewModel ?? KMBatchConvertPDFViewModel() var convertType: KMPDFConvertType = .word var fileName = filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } //获取page var pages:[Int] = [] for i in 0 ... document!.pageCount - 1 { pages.append(i+1) } convert.outputFolderPath = outputFolderPath convert.filePath = filePath convert.outputFileName = fileName convert.pages = pages switch settingData.convertPDFType { case .word: convertType = .word if settingData.layoutSettingType == .flowingText { convert.isAllInOneSheet = false } else { convert.isAllInOneSheet = true } case .excel: convertType = .excel if settingData.excelSetting == .separate { convert.isAllInOneSheet = false convert.isExtractTable = false } else if settingData.excelSetting == .format { convert.isAllInOneSheet = true convert.isExtractTable = false } else if settingData.excelSetting == .tables { convert.isAllInOneSheet = false convert.isExtractTable = true switch settingData.excelTablesType { case .oneTable: convert.extractTableIndex = 0 case .pageTable: convert.extractTableIndex = 1 case .allTable: convert.extractTableIndex = 2 default: KMPrint("未找到") } } case .ppt: convertType = .ppt case .csv: convertType = .csv if settingData.csvOnlyTables { convert.isExtractTable = true switch settingData.excelTablesType { case .oneTable: convert.extractTableIndex = 0 case .pageTable: convert.extractTableIndex = 1 case .allTable: convert.extractTableIndex = 2 default: KMPrint("未找到") } } else { convert.isExtractTable = false } case .image: convertType = .png case .html: convertType = .html case .rtf: convertType = .rtf default: KMPrint("不清楚") } convert.convertType = convertType KMPDFConvertManager.defaultManager.convert(convert: convert) { [unowned self] finished, error in if finished { // cancelButtonAction() } else { var errorString = "" let myError: NSError = error! as NSError if myError.code == 1 { errorString = NSLocalizedString("Password required or incorrect password. Please re-enter your password and try again", comment: "") } else if myError.code == 2 { errorString = NSLocalizedString("The license doesn't allow the permission", comment: "") } else if myError.code == 3 { errorString = NSLocalizedString("Malloc failure", comment: "") } else if myError.code == 4 { errorString = NSLocalizedString("Unknown error in processing conversion. Please try again later", comment: "") } else if myError.code == 5 { errorString = NSLocalizedString("Unknown error in processing PDF. Please try again later", comment: "") } else if myError.code == 6 { errorString = NSLocalizedString("File not found or could not be opened. Check if your file exists or choose another file to convert", comment: "") } else if myError.code == 7 { errorString = NSLocalizedString("File not in PDF format or corruptead. Change a PDF file and try again", comment: "") } else if myError.code == 8 { errorString = NSLocalizedString("Unsupported security scheme", comment: "") } else if myError.code == 9 { errorString = NSLocalizedString("Page not found or content error", comment: "") } else { errorString = NSLocalizedString("Table not found", comment: "") } let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Conversion Failed", comment: "") alert.informativeText = errorString alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() } } } if FileManager.default.fileExists(atPath: outputFolderPath) { NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } } } //MARK: 压缩 func compressExport(data: KMBatchSettingItemViewModel) { let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.compressFile(outputFolderPath: outputFolderPath!, data: (data as? KMBatchCompressViewModel)!, filesData: self.filesData!) } } func compressFile(outputFolderPath: String, data: KMBatchCompressViewModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" let docuemt = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) // if (docuemt?.isLocked)! && password != nil { // docuemt?.unlock(withPassword: password) // } var option = 120 switch data.type { case .large: option = 120 case .standard: option = 90 case .small: option = 60 case .minimum: option = 30 } docuemt?.writeOptimize(to: URL(fileURLWithPath: path), withOptions: [.imageQualityOption : option]) } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } //MARK: 安全 func securityExport(data: KMBatchSettingItemViewModel) { let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.securityFile(outputFolderPath: outputFolderPath!, data: data as! KMBatchSecurityViewModel, filesData: self.filesData!) } } func securityFile(outputFolderPath: String, data: KMBatchSecurityViewModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { let docuemt = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) if (docuemt != nil) { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" var options: [CPDFDocumentWriteOption : Any] = [:] //开启密码 if data.isOpenPassword && !data.openPasswordString.isEmpty { options.updateValue(data.openPasswordString, forKey: .userPasswordOption) } // //权限密码 if data.isPermission && !data.permissionString.isEmpty { options.updateValue(data.permissionString, forKey: .userPasswordOption) } // 限制打印 if data.restrictOptions.contains(.print) { options.updateValue(false, forKey: .allowsPrintingOption) } else { options.updateValue(true, forKey: .allowsPrintingOption) } //限制复制 if data.restrictOptions.contains(.copy) { options.updateValue(false, forKey: .allowsCopyingOption) } else { options.updateValue(true, forKey: .allowsCopyingOption) } let result = docuemt!.write(to: URL(fileURLWithPath: path), withOptions: options) if result { KMPrint("成功") } else { KMPrint("失败") } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } } } func waterMarkApplay(data: KMBatchSettingItemViewModel) { self.waterMarkFile(data: data as! KMWatermarkAdjectiveBaseModel, filesData: self.filesData!) } func waterMarkFile(data: KMWatermarkAdjectiveBaseModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) let pdfView = CPDFView() pdfView.document = document if (document != nil) { let watermarks = document!.watermarks() if (watermarks != nil && watermarks!.count > 0) { /// /// 替换水印 /// 替换 for i in 0 ..< watermarks!.count { let model = watermarks![i] document!.removeWatermark(model) } } } var pageRangeType: Int = 0 var pageRangeString: String = "0" switch item.pageRange.type { case .allPage: pageRangeType = 0 case .oddPage: pageRangeType = 1 case .evenPage: pageRangeType = 2 case.custom: pageRangeString = item.pageRange.selectPages.description case .currentPage: pageRangeType = 0 } data.pageRangeType = pageRangeType data.pageRangeString = pageRangeString KMWatermarkAdjectiveTools.apply(data, pdfView, pdfView.document.documentURL.path) { result in if (result) { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = "成功" alert.runModal() } else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "失败" alert.runModal() } } } } } func backgroundApplay(data: KMBatchSettingItemViewModel) { if (data == nil) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到背景模型" alert.runModal() return } let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.backgroundFile(outputFolderPath: outputFolderPath!, data: data as! KMBackgroundModel, filesData: self.filesData!) } } func backgroundFile(outputFolderPath: String, data: KMBackgroundModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { DispatchQueue.global().async { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) if document != nil { let property = document!.background() property!.scale = data.scale property!.rotation = CGFloat(-data.rotation) property!.opacity = data.opacity property?.xOffset = data.horizontalSpace property?.yOffset = data.verticalSpace property?.horizontalAlignment = UInt(data.horizontalMode) property?.verticalAlignment = UInt(data.verticalMode) if (data.type == .color) { property?.color = data.color property?.type = .color } else if (data.type == .file) { property?.setImage(NSImage(contentsOfFile: data.imagePath)) property?.type = .image } var pageRangeType: Int = 0 var pageRangeString: String = "0" switch item.pageRange.type { case .allPage: pageRangeType = 0 case .oddPage: pageRangeType = 1 case .evenPage: pageRangeType = 2 case.custom: pageRangeString = item.pageRange.selectPages.description case .currentPage: pageRangeType = 0 } data.pageRangeType = pageRangeType data.pageRangeString = pageRangeString let pagesString = KMWatermarkAdjectiveTools.findPagesString(data) if (pagesString.isEmpty) { property?.pageString = "0-\(document!.pageCount-1)" } else { property?.pageString = pagesString } property?.update() let result = document!.write(to: URL(fileURLWithPath: path)) if (result) { KMPrint("backgroundFile成功") } else { KMPrint("backgroundFile失败") } } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } } } func headAndFooterApplay(data: KMBatchSettingItemViewModel) { if (data == nil) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到" alert.runModal() return } let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.headAndFooterFile(outputFolderPath: outputFolderPath!, data: data as! KMHeaderFooterModel, filesData: self.filesData!) } } func headAndFooterFile(outputFolderPath: String, data: KMHeaderFooterModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { DispatchQueue.global().async { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) if document != nil { var property = document!.headerFooter() var fontSize = 0.0 var fontName: String = "" switch data.textFont { case .font(name: let name, size: let size): fontSize = size fontName = name break default: break } let font = NSFont.boldSystemFont(ofSize:fontSize) let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byCharWrapping let size: NSSize = "text".boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: [NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style]).size property?.margin = NSEdgeInsetsMake(max(data.topMargin-size.height, 0), data.leftMargin, max(data.bottomMargin-size.height, 0), data.rightMargin) let strings = KMHeaderFooterPreviewController.parseModel(model: data, pageCount: Int(document!.pageCount)) var count: Int = 0 var color: NSColor! switch data.textColor { case .color(red: let red, green: let green, blue: let blue, alpha: let alpha): color = NSColor(red: red, green: green, blue: blue, alpha: alpha) default: break } if (color == nil) { color = NSColor.black } for text in strings { property?.setText(text, at: UInt(count)) property?.setTextColor(color, at: UInt(count)) property?.setFontSize(fontSize, at: UInt(count)) property?.setFontName(fontName, at: UInt(count)) count += 1 } var pageRangeType: Int = 0 var pageRangeString: String = "0" switch item.pageRange.type { case .allPage: pageRangeType = 0 case .oddPage: pageRangeType = 1 case .evenPage: pageRangeType = 2 case.custom: pageRangeString = item.pageRange.selectPages.description case .currentPage: pageRangeType = 0 } data.pageRangeType = pageRangeType data.pageRangeString = pageRangeString let pagesString = KMWatermarkAdjectiveTools.findPagesString(data) if (pagesString.isEmpty) { property?.pageString = "0-\(document!.pageCount-1)" } else { property?.pageString = pagesString } property?.update() if (FileManager.default.fileExists(atPath: path)) { try?FileManager.default.removeItem(atPath: path) } let result = document!.write(to: URL(fileURLWithPath: path)) if (result) { KMPrint("headAndFooterFile成功") } else { KMPrint("headAndFooterFile失败") } } } } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } func batesApplay(data: KMBatchSettingItemViewModel) { if (data == nil) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到" alert.runModal() return } let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.batesFile(outputFolderPath: outputFolderPath!, data: data as! KMBatesModel, filesData: self.filesData!) } } func batesFile(outputFolderPath: String, data: KMBatesModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { DispatchQueue.global().async { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) if document != nil { var property = document!.bates() var fontSize = 0.0 var fontName: String = "" switch data.textFont { case .font(name: let name, size: let size): fontName = name fontSize = size break default: break } let font = NSFont.boldSystemFont(ofSize:fontSize) let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byCharWrapping let size: NSSize = "text".boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: [NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style]).size property?.margin = NSEdgeInsetsMake(max(data.topMargin-size.height, 0), data.leftMargin, max(data.bottomMargin-size.height, 0), data.rightMargin) let strings = [data.topLeftString, data.topCenterString, data.topRightString, data.bottomLeftString, data.bottomCenterString, data.bottomRightString] var count: Int = 0 var color: NSColor! switch data.textColor { case .color(red: let red, green: let green, blue: let blue, alpha: let alpha): color = NSColor(red: red, green: green, blue: blue, alpha: alpha) default: break } if (color == nil) { color = NSColor.black } for text in strings { property?.setText(text, at: UInt(count)) property?.setTextColor(color, at: UInt(count)) property?.setFontSize(fontSize, at: UInt(count)) property?.setFontName(fontName, at: UInt(count)) count += 1 } var pageRangeType: Int = 0 var pageRangeString: String = "0" switch item.pageRange.type { case .allPage: pageRangeType = 0 case .oddPage: pageRangeType = 1 case .evenPage: pageRangeType = 2 case.custom: pageRangeString = item.pageRange.selectPages.description case .currentPage: pageRangeType = 0 } data.pageRangeType = pageRangeType data.pageRangeString = pageRangeString let pagesString = KMWatermarkAdjectiveTools.findPagesString(data) if (pagesString.isEmpty) { property?.pageString = "0-\(document!.pageCount-1)" } else { property?.pageString = pagesString } property?.update() if (FileManager.default.fileExists(atPath: path)) { try?FileManager.default.removeItem(atPath: path) } let result = document!.write(to: URL(fileURLWithPath: path)) if (result) { KMPrint("batesFile成功") } else { KMPrint("batesFile失败") } } } } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } } func removeApplay(data: KMBatchSettingItemViewModel) { if (data == nil) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "没有找到" alert.runModal() return } let panel = NSOpenPanel() let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil) button.state = .on panel.accessoryView = button panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.beginSheetModal(for: self.window!) { [self] response in if response == .cancel { return } let outputFolderPath = panel.url?.path self.removeFile(outputFolderPath: outputFolderPath!, data: data as! KMBatchRemoveViewModel, filesData: self.filesData!) } } func removeFile(outputFolderPath: String, data: KMBatchRemoveViewModel, filesData: [KMBatchProcessingTableViewModel]?) { if filesData?.count != 0 { for item in filesData! { // DispatchQueue.global().async { var fileName = item.filePath.deletingPathExtension.lastPathComponent if ((fileName.isEmpty)) { fileName = NSLocalizedString("Untitled", comment: "") } let path = outputFolderPath + "/" + fileName + ".pdf" let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath)) if document != nil { if (document!.allowsPrinting == false || document!.allowsCopying == false) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "此文档不允许修改" alert.runModal() return } if (data.options.contains(.security)) { } if (data.options.contains(.batesNumber)) { let property = document!.bates() property?.clear() } if (data.options.contains(.headerAndFooter)) { let property = document!.headerFooter() property?.clear() } if (data.options.contains(.background)) { let property = document!.background() property?.clear() } if (data.options.contains(.watermark)) { let array: Array = document!.watermarks() ?? [] for model in array { document!.removeWatermark(model) } } if (FileManager.default.fileExists(atPath: path)) { try?FileManager.default.removeItem(atPath: path) } let result = document!.write(to: URL(fileURLWithPath: path)) if (result) { KMPrint("removeFile成功") } else { KMPrint("removeFile失败") } NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)]) } // } } } } }