// // KMConvertWindowController.swift // PDF Reader Pro // // Created by liujiajie on 2023/11/8. // import Cocoa typealias convertBatchCallBack = () -> Void let kPreviewMaxWidth = 237.0 let kPreviewMaxHeight = 325.0 let kConvertFileSavePath = (kTempSavePath?.stringByAppendingPathComponent("convert.pdf")) @objcMembers class KMConvertWindowController: NSWindowController, NSTextFieldDelegate, NSWindowDelegate, NSComboBoxDelegate{ @IBOutlet var prePDFViewHeight: NSLayoutConstraint! @IBOutlet var prePDFViewWidth: NSLayoutConstraint! var prePDFView: CPDFView! @IBOutlet var prePdfBGView: NSView! @IBOutlet var currentPageIndexTextField: NSTextField! @IBOutlet var totalPageCountLabel: NSTextField! @IBOutlet var formatLabel: NSTextField! @IBOutlet var formatSelectButton: NSPopUpButton! @IBOutlet var imageDPISelectButton: NSPopUpButton! @IBOutlet var moreButton: NSButton! @IBOutlet var buttonBottemOffset: NSLayoutConstraint! @IBOutlet var buttonTopOffset: NSLayoutConstraint! @IBOutlet var moreConvertBox: NSBox! @IBOutlet var moreConvertLabel: NSTextField! @IBOutlet var pageRangLabel: NSTextField! @IBOutlet var pageRangeBox: NSComboBox! @IBOutlet var convertButton: NSButton! @IBOutlet var cancelButton: NSButton! @IBOutlet var batchButton: NSButton! @IBOutlet var upgradeButton: NSButton! @IBOutlet var separateStypeTopOffset: NSLayoutConstraint! @IBOutlet var separateButton: NSButton! @IBOutlet var singleButton: NSButton! @IBOutlet var separateStypeBox: NSBox! @IBOutlet var extractTableButton: NSButton! @IBOutlet var extractTableTopOffset: NSLayoutConstraint! @IBOutlet var separateStypeLabel: NSTextField! @IBOutlet var excelStyleBox: NSBox! @IBOutlet var onlyTextBtn: NSButton! @IBOutlet var onlyTableBtn: NSButton! @IBOutlet var allContentBtn: NSButton! @IBOutlet var tableMenu1: NSMenuItem! @IBOutlet var tableMenu2: NSMenuItem! @IBOutlet var tableMenu3: NSMenuItem! @IBOutlet var allContentMenu2: NSMenuItem! @IBOutlet var allContentMenu3: NSMenuItem! @IBOutlet var tableMenu: NSPopUpButton! @IBOutlet var allContentMenu: NSPopUpButton! @IBOutlet var ocrBox: NSBox! @IBOutlet var ocrLabel: NSTextField! @IBOutlet var ocrButton: NSButton! @IBOutlet var ocrLanguageBox: NSPopUpButton! @IBOutlet var ocrTopOffset: NSLayoutConstraint! var isAllInOneSheet = false var modalSession: NSApplication.ModalSession? var pdfDocument: CPDFDocument? var maskView: KMBookletMaskView? var convertType: KMConvertType = .Word var imageDPINumber: Int = 0 var callBackBlock: convertBatchCallBack? var currentPage: CPDFPage? var savePath: String = "" var lockPassword: String = "" var tempPDFDocument: CPDFDocument? var excelContentOption: CPDFConvertExcelContentOptions? var excelWorksheetOption: CPDFConvertExcelWorksheetOptions? private var fileAttri_: KMFileAttribute? private var ocrLanguage_: COCRLanguage = .english deinit { #if DEBUG NSLog("====KMConvertWindowController==deinit") #endif } convenience init(documemtV:CPDFDocument, currentPage:CPDFPage, convertT:KMConvertType, handle:@escaping convertBatchCallBack) { self.init(windowNibName: "KMConvertWindowController") if (documemtV.documentURL != nil) { let pageIndex = documemtV.index(for: currentPage) self.pdfDocument = CPDFDocument(url: documemtV.documentURL) let isLoc: Bool = self.pdfDocument!.isLocked if (!documemtV.isLocked && isLoc) { self.lockPassword = documemtV.password self.pdfDocument?.unlock(withPassword: self.lockPassword) } self.currentPage = self.pdfDocument?.page(at: pageIndex ) } else { self.pdfDocument = documemtV self.currentPage = currentPage } self.callBackBlock = handle if convertT.rawValue > 15 || convertT.rawValue < 0 { self.convertType = .Word } else { self.convertType = convertT } } convenience init(localPath:String, handle:@escaping convertBatchCallBack) { self.init(windowNibName: "KMConvertWindowController") self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: localPath)) self.callBackBlock = handle let isLoc: Bool = self.pdfDocument!.isLocked if (isLoc) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) { let url = self.pdfDocument?.documentURL KMBaseWindowController.checkPassword(url: url!, type: .owner) { [weak self] success, resultPassword in if success { self?.lockPassword = resultPassword self?.pdfDocument?.unlock(withPassword: resultPassword) self?.currentPage = self?.pdfDocument?.page(at: 0) self?.convertType = .Word } } } } } override func windowDidLoad() { super.windowDidLoad() let preView: CPDFView = CPDFView(frame: self.prePdfBGView.bounds) self.prePdfBGView.addSubview(preView) self.prePDFView = preView self.ocrBox.fillColor = .gridColor localizedLanguage() self.currentPageIndexTextField.delegate = self; pageRangLabel.stringValue = KMLocalizedString("Page Range:", nil) pageRangeBox.addItem(withObjectValue: KMLocalizedString("All Pages", nil)) pageRangeBox.addItem(withObjectValue: KMLocalizedString("Current Page", nil)) pageRangeBox.addItem(withObjectValue: KMLocalizedString("Odd Pages Only", nil)) pageRangeBox.addItem(withObjectValue: KMLocalizedString("Even Pages Only", nil)) pageRangeBox.addItem(withObjectValue: KMLocalizedString("e.g. 1,3-5,10", nil)) (pageRangeBox.cell as? NSComboBoxCell)?.placeholderString = KMLocalizedString("e.g. 1,3-5,10", nil) pageRangeBox.selectItem(at: 0) pageRangeBox.isEditable = false ocrLanguageBox.selectItem(at: 2) ocrLabel.textColor = KMAppearance.Layout.h2Color() ocrLanguageBox.isEnabled = false ocrButton.state = .off let isLoc: Bool = self.pdfDocument!.isLocked if (isLoc) { self.showWaitting() DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { let url = URL(fileURLWithPath: self.pdfDocument!.documentURL.path) KMBaseWindowController.checkPassword(url: url, type: .owner) { result, password in self.hideWaitting() if password.count > 0 { let unlockSuccess: Bool = ((self.pdfDocument?.unlock(withPassword: password)) != nil) self.lockPassword = password if unlockSuccess { self.currentPage = self.pdfDocument?.page(at: 0) } self.configuView() } else { self.buttonClicked_Cancel(self.cancelButton) } } } } else { self.configuView() } if #available(macOS 10.14, *) { let appearanceName = NSApp.effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) if appearanceName == .darkAqua { moreConvertLabel.textColor = NSColor.white } } isAllInOneSheet = false separateButton.state = .on singleButton.state = .off allContentBtn.state = .on allContentMenu.isEnabled = true tableMenu.isEnabled = false excelContentOption = .allContent excelWorksheetOption = .forEachPage NotificationCenter.default.addObserver(self, selector: #selector(PDFViewDocumentChangedNotification(notification:)), name: NSNotification.Name.CPDFViewPageChanged, object: nil) } @objc func PDFViewDocumentChangedNotification(notification: NSNotification) { let pageIndex = self.prePDFView.currentPageIndex+1 self.currentPageIndexTextField.stringValue = "\(pageIndex)" } func windowShouldClose(_ sender: NSWindow) -> Bool { self.dismissSheet() return true } func localizedLanguage() { formatLabel.stringValue = KMLocalizedString("Format:", nil) separateButton.title = KMLocalizedString("Convert each page to a separate worksheet", nil) singleButton.title = KMLocalizedString("Convert all pages to a single worksheet", nil) ocrBox.title = KMLocalizedString("OCR Settings", nil) ocrLabel.stringValue = KMLocalizedString("Language Option", nil) + ":" ocrButton.title = KMLocalizedString("Recognize text", nil) separateStypeLabel.stringValue = KMLocalizedString("Excel Worksheet Settings", nil) extractTableButton.title = KMLocalizedString("Extract Tables Only", nil) batchButton.title = KMLocalizedString("Batch", nil) cancelButton.title = KMLocalizedString("Cancel", nil) convertButton.title = KMLocalizedString("Convert", nil) upgradeButton.title = KMLocalizedString("Upgrade", nil) onlyTextBtn.title = KMLocalizedString("Only Text", nil) onlyTableBtn.title = KMLocalizedString("Only Table", nil) allContentBtn.title = KMLocalizedString("All Content", nil) tableMenu1.title = KMLocalizedString("Create Sheet for each Table", nil) tableMenu2.title = KMLocalizedString("Create Sheet for each Page", nil) allContentMenu2.title = KMLocalizedString("Create Sheet for each Page", nil) tableMenu3.title = KMLocalizedString("Create single Sheet for File", nil) allContentMenu3.title = KMLocalizedString("Create single Sheet for File", nil) } func hideWaitting() { maskView?.removeFromSuperview() } func showWaitting() { if maskView == nil { maskView = KMBookletMaskView(frame: CGRect(x: 0, y: 0, width: self.window?.frame.size.width ?? 0, height: self.window?.frame.size.height ?? 0)) } self.window?.contentView?.addSubview(maskView!) } func configuView() { self.prePDFView.autoScales = true self.prePDFView.wantsLayer = true self.prePDFView.document = self.pdfDocument self.imageDPISelectButton.removeAllItems() self.formatSelectButton.removeAllItems() let dpiArray = ["50 dpi", "72 dpi", "96 dpi", "150 dpi", "300 dpi", "600 dpi"] let formArray = ["Excel (.xlsx)", "PowerPoint (.pptx)", "RTF (.rtf)", "CSV (.csv)", "Html (.html)", "Text (.txt)", "JPEG (.jpeg)", "JPG (.jpg)", "PNG (.png)", "GIF (.gif)", "TIFF (.tiff)", "TGA (.tga)", "BMP (.bmp)", "JPEG-2000 (.jp2)","Json(.json)"] for (index, string) in formArray.enumerated() { let item = NSMenuItem() item.title = string item.target = self item.tag = index + 1 self.formatSelectButton.menu?.addItem(item) } var isShowAdvanced = false let wordItem = NSMenuItem() wordItem.title = "Word (.docx)" wordItem.target = self var isShowUpgrade = false var convertSample: KMConvertType = .Word #if VERSION_FREE #if VERSION_DMG // 桌机版 wordItem.tag = convertSample.rawValue isShowAdvanced = true if IAPProductsManager.default().isAvailableAllFunction() { if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { convertSample = .AdvancedWord wordItem.tag = convertSample.rawValue isShowAdvanced = false } else { isShowUpgrade = true } } else { isShowUpgrade = true } #else // 免费版 convertSample = .Word wordItem.tag = convertSample.rawValue isShowAdvanced = true if IAPProductsManager.default().isAvailableAllFunction() { if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { convertSample = .AdvancedWord wordItem.tag = convertSample.rawValue isShowAdvanced = false } else { isShowUpgrade = true } } else { isShowUpgrade = true } #endif #else convertSample = .Word wordItem.tag = convertSample.rawValue // 付费版 isShowAdvanced = true if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { isShowAdvanced = false convertSample = .AdvancedWord wordItem.tag = convertSample.rawValue } else { isShowUpgrade = true } #endif if wordItem.title != "" { if isShowAdvanced { let originStr = " \(KMLocalizedString("Standard", nil)) " let str = KMLocalizedString("Word (.docx)", nil) let attributedStr = NSMutableAttributedString(string: "\(str) \(originStr)") attributedStr.addAttribute(NSAttributedString.Key.backgroundColor, value: NSColor(red: 40/255.0, green: 193.0/255.0, blue: 107.0/255.0, alpha: 1.0), range: NSMakeRange(str.count + 2, originStr.count)) attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.white, range: NSMakeRange(str.count + 2, originStr.count)) let item = NSMenuItem() item.attributedTitle = attributedStr item.target = self item.tag = wordItem.tag self.formatSelectButton.menu?.insertItem(item, at: 0) } else { self.formatSelectButton.menu?.insertItem(wordItem, at: 0) } } if !isShowUpgrade { self.upgradeButton.isHidden = true } var selectIndex = 0 if isShowAdvanced { let originStr = " \(NSLocalizedString("Advanced", comment: "")) " let str = NSLocalizedString("Word (.docx)", comment: "") let attributedStr = NSMutableAttributedString(string: "\(str) \(originStr)") attributedStr.addAttribute(NSAttributedString.Key.backgroundColor, value: NSColor(red: 245.0/255.0, green: 142.0/255.0, blue: 38.0/255.0, alpha: 1.0), range: NSMakeRange(str.count + 2, originStr.count)) attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.white, range: NSMakeRange(str.count + 2, originStr.count)) let item = NSMenuItem() item.attributedTitle = attributedStr item.target = self convertSample = .AdvancedWord item.tag = convertSample.rawValue self.formatSelectButton.menu?.insertItem(item, at: 0) } if self.convertType == .Word { selectIndex = 0 } else { selectIndex = self.convertType.rawValue if isShowAdvanced { selectIndex += 1 } if wordItem.title == "" { selectIndex -= 1 } } self.formatSelectButton.selectItem(at: selectIndex) let item = self.formatSelectButton.selectedItem self.convertType = KMConvertType(rawValue: item?.tag ?? 0) ?? .Word self.imageDPISelectButton.isHidden = true self.buttonTopOffset.constant = -26 self.imageDPISelectButton.addItems(withTitles: dpiArray) self.imageDPISelectButton.selectItem(at: 3) self.imageDPINumber = 150 self.totalPageCountLabel.stringValue = " / \(self.pdfDocument?.pageCount ?? 1)" self.totalPageCountLabel.textColor = KMAppearance.Layout.h2Color() self.updataView() self.prePDFView.go(to: currentPage) let pageIndex = self.prePDFView.currentPageIndex+1 self.currentPageIndexTextField.stringValue = "\(pageIndex)" if let documentURL = self.pdfDocument?.documentURL{ self.pdfDocument = CPDFDocument(url: documentURL) if !lockPassword.isEmpty && lockPassword.count > 0{ self.pdfDocument?.unlock(withPassword: lockPassword) } self.prePDFView.document = self.pdfDocument self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = documentURL.path } self.prePDFView.setDisplay(.singlePage) self.prePDFView.layoutDocumentView() } func updataView() { var moreLabelString: String = "" var offset: CGFloat = 0 excelStyleBox.isHidden = true #if VERSION_FREE // 座机版 if !IAPProductsManager.default().isAvailableAllFunction() { moreLabelString = String(format: "%@ %@", KMLocalizedString("The first 10 pages for free"), KMLocalizedString("Unlimited Convert")) } else { if !IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { if .Word == self.convertType || self.convertType == .AdvancedWord || .Excel == self.convertType || .PPT == self.convertType || .CSV == self.convertType || .RTF == self.convertType || .GIF == self.convertType || .TIFF == self.convertType || .JP2 == self.convertType || .BMP == self.convertType || .TGA == self.convertType || .Json == self.convertType { moreLabelString = String(format: "%@ %@", KMLocalizedString("The first 10 pages for free"), KMLocalizedString("Unlimited Convert")) } } } #else // 付费版 if !(IAPProductsManager.default().isAvailableAdvancedPDFToOffice()) { if .Word == self.convertType || self.convertType == .AdvancedWord || .Excel == self.convertType || .PPT == self.convertType || .CSV == self.convertType || .RTF == self.convertType || .GIF == self.convertType || .TIFF == self.convertType || .JP2 == self.convertType || .BMP == self.convertType || .TGA == self.convertType || .Json == self.convertType { moreLabelString = String(format: "%@ %@", KMLocalizedString("The first 10 pages for free"), KMLocalizedString("Unlimited Convert")) } } #endif if convertType.rawValue >= 7 && convertType.rawValue <= 14 { offset += imageDPISelectButton.frame.size.height imageDPISelectButton.isHidden = false buttonTopOffset.constant = 5 } else { imageDPISelectButton.isHidden = true buttonTopOffset.constant = -26 } if moreLabelString.count < 1 { offset += 5 moreConvertBox.isHidden = true moreButton.isHidden = true } else { offset += (moreButton.frame.size.height + 5) moreConvertBox.isHidden = false moreButton.isHidden = false moreConvertLabel.stringValue = moreLabelString if let range = moreLabelString.range(of: NSLocalizedString("Unlimited Convert", comment: "")) { let newR: NSRange = moreLabelString.nsRange(from: range)! let attributedStr = NSMutableAttributedString(string: moreLabelString) attributedStr.addAttribute(.foregroundColor, value: NSColor.labelColor, range: NSRange(location: 0, length: newR.location - 1)) attributedStr.addAttribute(.foregroundColor, value: NSColor(red: 8/255, green: 124/255, blue: 1, alpha: 1), range: newR) attributedStr.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: newR) moreConvertLabel.attributedStringValue = attributedStr } } if .Excel == convertType { separateStypeTopOffset.constant = separateStypeBox.frame.size.height + ocrBox.frame.size.height + 16 + 58 extractTableTopOffset.constant = separateStypeBox.frame.size.height + 50 ocrTopOffset.constant = 128 separateStypeBox.isHidden = true extractTableButton.isHidden = true excelStyleBox.isHidden = false separateStypeLabel.isHidden = false ocrBox.isHidden = false separateStypeLabel.stringValue = NSLocalizedString("Excel Worksheet Settings", comment: "") separateButton.title = NSLocalizedString("Convert each page to a separate worksheet", comment: "") singleButton.title = NSLocalizedString("Convert all pages to a single worksheet", comment: "") buttonClicked_extractTable(extractTableButton) } else if .AdvancedWord == convertType { singleButton.setTitleColor(NSColor.labelColor) separateButton.setTitleColor(NSColor.labelColor) separateStypeLabel.textColor = NSColor.labelColor separateButton.state = NSControl.StateValue.on singleButton.isEnabled = true separateButton.isEnabled = true isAllInOneSheet = false separateStypeTopOffset.constant = separateStypeBox.frame.size.height + 40 + ocrBox.frame.size.height ocrTopOffset.constant = separateStypeBox.frame.size.height + 40 extractTableButton.isHidden = true separateStypeBox.isHidden = false separateStypeLabel.isHidden = false separateStypeLabel.stringValue = NSLocalizedString("Layout Settings", comment: "") separateButton.title = NSLocalizedString("Retain Flowing Text", comment: "") singleButton.title = NSLocalizedString("Retain Page Layout", comment: "") ocrBox.isHidden = false } else if .Json == convertType { singleButton.setTitleColor(NSColor.labelColor) separateButton.setTitleColor(NSColor.labelColor) separateStypeLabel.textColor = NSColor.labelColor separateButton.state = NSControl.StateValue.on singleButton.isEnabled = true separateButton.isEnabled = true isAllInOneSheet = false separateStypeTopOffset.constant = separateStypeBox.frame.size.height + 40 + ocrBox.frame.size.height ocrTopOffset.constant = separateStypeBox.frame.size.height + 40 extractTableButton.isHidden = true separateStypeBox.isHidden = false separateStypeLabel.isHidden = false separateStypeLabel.stringValue = NSLocalizedString("Json Worksheet Settings", comment: "") separateButton.title = NSLocalizedString("Extract text content", comment: "") singleButton.title = NSLocalizedString("Extract tables", comment: "") ocrBox.isHidden = false } else if .CSV == convertType { separateStypeTopOffset.constant = extractTableButton.frame.size.height + 30 extractTableTopOffset.constant = 12 extractTableButton.isHidden = false separateStypeBox.isHidden = true separateStypeLabel.isHidden = true ocrBox.isHidden = true } else if (.PPT == convertType || .RTF == convertType) { separateStypeTopOffset.constant = ocrBox.frame.size.height + 10 ocrTopOffset.constant = 10 separateStypeBox.isHidden = true extractTableButton.isHidden = true separateStypeLabel.isHidden = true ocrBox.isHidden = false } else if (.HTML == convertType || .Text == convertType) { separateStypeTopOffset.constant = ocrBox.frame.size.height + 10 ocrTopOffset.constant = 10 separateStypeBox.isHidden = true extractTableButton.isHidden = true separateStypeLabel.isHidden = true ocrBox.isHidden = false } else { separateStypeTopOffset.constant = 10 separateStypeBox.isHidden = true extractTableButton.isHidden = true separateStypeLabel.isHidden = true ocrBox.isHidden = true } buttonBottemOffset.constant = offset } @IBAction func buttonClicked_extractTable(_ sender: NSButton) { if extractTableButton.state == .on { singleButton.setTitleColor(KMAppearance.Layout.b15_1Color()) separateButton.setTitleColor(KMAppearance.Layout.b15_1Color()) separateStypeLabel.textColor = KMAppearance.Layout.b15_1Color() singleButton.isEnabled = false separateButton.isEnabled = false separateButton.state = .off singleButton.state = .off } else { singleButton.setTitleColor(NSColor.labelColor) separateButton.setTitleColor(NSColor.labelColor) separateStypeLabel.textColor = NSColor.labelColor separateButton.state = .on singleButton.isEnabled = true separateButton.isEnabled = true isAllInOneSheet = false } } @IBAction func buttonClicked_Cancel(_ sender: NSButton) { dismissSheet() } func dismissSheet() { if FileManager.default.fileExists(atPath: kConvertFileSavePath ?? "") { do { try FileManager.default.removeItem(atPath: kConvertFileSavePath ?? "") } catch { print("Error removing item at path: (error.localizedDescription)") } } // if self.prePDFView.document != nil { // self.prePDFView.document = nil // } // if self.tempPDFDocument != nil { // self.tempPDFDocument = nil // } self.km_quick_endSheet() } func showCriticalAlert(_ alertMsg: String?) { let alert = NSAlert() alert.alertStyle = .critical if let msg = alertMsg { alert.informativeText = msg } else { let st = self.pdfDocument?.documentURL.lastPathComponent.count ?? 0 > 0 ? self.pdfDocument?.documentURL.lastPathComponent : KMLocalizedString("Untitled.pdf", nil) alert.messageText = String(format: "%@ %@", st!, KMLocalizedString("Invalid page range or the page number is out of range. Please try again.", nil)) } alert.runModal() } func produceNewPDF(with pagesArray: [CPDFPage]) { tempPDFDocument = nil // if self.tempPDFDocument == nil || self.tempPDFDocument!.isLocked { self.tempPDFDocument = CPDFDocument() // } var indexs = IndexSet() let pageCount = self.pdfDocument?.pageCount ?? 0 for addedPage in pagesArray { // tempPDFDocument?.insertPageObject(addedPage, at: tempPDFDocument!.pageCount) let idx = addedPage.pageIndex() if idx >= 0 && idx < pageCount { indexs.insert(IndexSet.Element(idx)) } } // self.tempPDFDocument?.removePage(at: IndexSet(integersIn: 0..<(Int(self.tempPDFDocument?.pageCount ?? 0)))) _ = self.tempPDFDocument?.importPages(indexs, from: self.pdfDocument, at: 0) self.prePDFView.document = self.tempPDFDocument self.prePDFView.layoutDocumentView() self.prePDFView.goToFirstPage(nil) self.currentPageIndexTextField.stringValue = "1" self.totalPageCountLabel.stringValue = " / \(self.tempPDFDocument!.pageCount)" } @IBAction func buttonClicked_FormatSelect(_ sender: NSButton) { guard let item = self.formatSelectButton.selectedItem else { return } self.convertType = KMConvertType(rawValue: item.tag) ?? .Word updataView() } func transform(with string: String) { if string == KMLocalizedString("Create Sheet for each Table", nil) { self.excelWorksheetOption = .forEachTable } else if string == KMLocalizedString("Create Sheet for each Page", nil) { self.excelWorksheetOption = .forEachPage } else if string == KMLocalizedString("Create single Sheet for File", nil) { self.excelWorksheetOption = .forTheDocument } } @IBAction func buttonClicked_excelStyle(_ sender: NSButton) { if sender.isEqual(self.onlyTextBtn) { self.tableMenu.isEnabled = false self.allContentMenu.isEnabled = false self.excelContentOption = .onlyText self.excelWorksheetOption = .forEachTable } else if (sender.isEqual(self.onlyTableBtn)) { self.tableMenu.isEnabled = true self.allContentMenu.isEnabled = false self.excelContentOption = .onlyTable transform(with: self.tableMenu.selectedItem?.title ?? "") } else if (sender.isEqual(self.allContentBtn)) { self.tableMenu.isEnabled = false self.allContentMenu.isEnabled = true self.excelContentOption = .allContent transform(with: self.allContentMenu.selectedItem?.title ?? "") } } @IBAction func buttonClicked_tableMenu(_ sender: NSButton) { transform(with: self.tableMenu.selectedItem?.title ?? "") } @IBAction func buttonClicked_allContentMenu(_ sender: NSButton) { transform(with: self.allContentMenu.selectedItem?.title ?? "") } @IBAction func buttonClicked_DpiSelect(_ sender: NSPopUpButton) { let index = sender.indexOfSelectedItem var dpi = 0 if index == 0 { dpi = 50 } else if index == 1 { dpi = 72 } else if index == 2 { dpi = 96 } else if index == 3 { dpi = 150 } else if index == 4 { dpi = 300 } else if index == 5 { dpi = 600 } self.imageDPINumber = dpi } @IBAction func buttonClick_PreviousPage(_ sender: NSButton) { if self.prePDFView.canGoToPreviousPage() { self.prePDFView.goToPreviousPage(nil) let currentIndex = self.prePDFView.document?.index(for: self.prePDFView.currentPage()) ?? 0 self.currentPageIndexTextField.stringValue = "\(currentIndex + 1)" } } @IBAction func buttonClicked_NextPage(_ sender: NSButton) { if self.prePDFView.canGoToNextPage() { self.prePDFView.goToNextPage(nil) let currentIndex = self.prePDFView.document?.index(for: self.prePDFView.currentPage()) self.currentPageIndexTextField.stringValue = "\((currentIndex ?? 0) + 1)" } } @IBAction func buttonClicked_Batch(_ sender: NSButton) { if !IAPProductsManager.default().isAvailableAllFunction() { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return } if self.pdfDocument?.documentURL == nil { NSSound.beep() return } if self.callBackBlock != nil { self.callBackBlock!() self.callBackBlock = nil } dismissSheet() } @IBAction func buttonClicked_Convert(_ sender: Any) { self.window?.makeFirstResponder(self.prePDFView) if (4 == pageRangeBox.indexOfSelectedItem) { if self.fileAttri_ == nil { self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = self.pdfDocument?.documentURL.path ?? "" } // fileAttri_.pdfDocument = self.pdfDocument self.fileAttri_?.bAllPage = false self.fileAttri_?.pagesType = .custom self.fileAttri_?.pagesString = pageRangeBox.stringValue let pages = self.fileAttri_?.fetchSelectPages() ?? [] if pages.isEmpty { return } } let openPanel = NSOpenPanel() openPanel.canChooseFiles = false openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.beginSheetModal(for: self.window!) { result in if result == .OK { self.savePath = openPanel.url!.path self.beginConvert() } } } func beginConvert() { var isLimitConvert = false #if VERSION_FREE #if VERSION_DMG // 桌机版 if IAPProductsManager.default().isAvailableAllFunction() { if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { isLimitConvert = false } else { if (.PNG == self.convertType || .JPEG == self.convertType || .JPG == self.convertType || .HTML == self.convertType || .Text == self.convertType || .Word == self.convertType) { isLimitConvert = false } else { isLimitConvert = true } } } else { isLimitConvert = true } #else // 免费版 if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() == false { isLimitConvert = true } #endif #else // 付费版 if IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { isLimitConvert = false } else { if (.PNG == self.convertType || .JPEG == self.convertType || .JPG == self.convertType || .HTML == self.convertType || .Text == self.convertType || .Word == self.convertType) { isLimitConvert = false } else { isLimitConvert = true } } #endif self.showWaitting() let pages = NSMutableArray() DispatchQueue.global(qos: .background).async { [self] in let filePath = getConvertFileSavePath() if (FileManager.default.fileExists(atPath: filePath)) { try?FileManager.default.removeItem(atPath: filePath) } if self.prePDFView.document.write(toFile: filePath) { for i in 0..= 10 { for i in 0..<10 { selectPages.append(pages[i] as! Int) } } else { selectPages = pages as! [Int] } } else { selectPages = pages as! [Int] } var convert = KMPDFConvert() if self.convertType == .Json { convert = KMPDFConvertJson() convert.isAllInOneSheet = self.isAllInOneSheet } else if self.convertType == .AdvancedWord || self.convertType == .Word { convert = KMPDFConvertWord() let data = convert as? KMPDFConvertWord data?.layoutOptions = self.isAllInOneSheet ? .retainPageLayout : .retainFlowingText convert.isAllInOneSheet = self.isAllInOneSheet } else if self.convertType == .Excel { convert = KMPDFConvertExcel() convert.isExtractText = false convert.isExtractTable = false convert.isAllInOneSheet = self.excelWorksheetOption == .forTheDocument if self.onlyTextBtn.state == .on { convert.isExtractText = true } else if self.onlyTableBtn.state == .on { convert.isExtractTable = true convert.extractTableIndex = self.excelWorksheetOption?.rawValue ?? 0 } } else if self.convertType == .PPT { convert = KMPDFConvertPPT() } else if self.convertType == .Text { convert = KMPDFConvertText() } else if self.convertType == .RTF { convert = KMPDFConvertRTF() } else if self.convertType == .HTML { convert = KMPDFConvertHTML() } else if self.convertType == .CSV { convert = KMPDFConvertCSV() convert.isExtractTable = self.extractTableButton.state == .on } else { if self.convertType == .JPEG || self.convertType == .JPG || self.convertType == .PNG || self.convertType == .GIF || self.convertType == .TIFF || self.convertType == .TGA || self.convertType == .BMP || self.convertType == .JP2 { convert = KMPDFConvertImage() let data = convert as? KMPDFConvertImage if self.convertType == .JPEG { data?.imageType = .JPEG } else if self.convertType == .JPG { data?.imageType = .JPEG } else if self.convertType == .PNG { data?.imageType = .PNG } // else if self.convertType == .GIF { // } else if self.convertType == .TIFF { // } else if self.convertType == .TGA { // } else if self.convertType == .BMP { // } data?.imageDpi = self.imageDPINumber } } convert.isAllowOCR = self.ocrButton.state == .on convert.ocrLanguage = convert.isAllowOCR ? self.ocrLanguage_ : .english convert.filePath = filePath convert.pages = selectPages // convert.isAllInOneSheet = self.isAllInOneSheet if self.convertType == .Word { convert.type = 0 } else { convert.type = 1 } // convert.isExtractTable = self.extractTableButton.state == .on convert.outputFolderPath = self.savePath convert.outputFileName = (self.pdfDocument?.documentURL.deletingPathExtension().lastPathComponent) ?? NSLocalizedString("Untitled", comment: "") if self.convertType == .AdvancedWord { convert.convertType = .word } else if self.convertType == .JPEG || self.convertType == .JPG || self.convertType == .PNG || self.convertType == .GIF || self.convertType == .TIFF || self.convertType == .TGA || self.convertType == .BMP || self.convertType == .JP2 { convert.convertType = KMPDFConvertType(rawValue: self.convertType.rawValue) ?? .word convert.options = [KMPDFConvertOptionsKeyImageDPI : self.imageDPINumber, KMPDFConvertOptionsKeyImageWithAnnotation : true] as [String : Any] } else { convert.convertType = KMPDFConvertType(rawValue: self.convertType.rawValue) ?? .word } if self.convertType == .Excel { convert.excelContentOption = self.excelContentOption convert.excelWorksheetOption = self.excelWorksheetOption } convert.password = self.lockPassword KMPDFConvertManager.defaultManager.convert(convert: convert) { [weak self] (finished, error) in self?.hideWaitting() if finished { self?.dismissSheet() if FileManager.default.fileExists(atPath: convert.outputFilePath) { let workspace = NSWorkspace.shared let url = URL(fileURLWithPath: convert.outputFilePath) workspace.activateFileViewerSelecting([url]) } } else if let error = error { let err: NSError = error as NSError var erroeString = "" switch err.code { case CPDFConverterEncryptError: erroeString = NSLocalizedString("Password required or incorrect password. Please re-enter your password and try again", comment: "") break case CPDFConverterPermissionError: erroeString = NSLocalizedString("The license doesn't allow the permission", comment: "") break case CPDFConverterMallocError: erroeString = NSLocalizedString("Malloc failure", comment: "") break case CPDFConverterUnknownError: erroeString = NSLocalizedString("Unknown error in processing conversion. Please try again later", comment: "") break case CPDFConverterPDFUnknownError: erroeString = NSLocalizedString("Unknown error in processing PDF. Please try again later", comment: "") break case CPDFConverterPDFFileError: erroeString = NSLocalizedString("File not found or could not be opened. Check if your file exists or choose another file to convert", comment: "") break case CPDFConverterPDFFormatError: erroeString = NSLocalizedString("File not in PDF format or corruptead. Change a PDF file and try again", comment: "") break case CPDFConverterPDFSecurityError: erroeString = NSLocalizedString("Unsupported security scheme", comment: "") break case CPDFConverterPDFPageError: erroeString = NSLocalizedString("Page not found or content error", comment: "") break default: erroeString = NSLocalizedString("Table not found", comment: "") break } let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Conversion Failed", comment: "") alert.informativeText = erroeString alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) if #available(OSX 10.14, *) { alert.beginSheetModal(for: self?.window! ?? NSWindow.currentWindow(), completionHandler: nil) } else { alert.runModal() } } } } } } func getConvertFileSavePath() -> String { var path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last path?.append("/") path?.append(Bundle.main.bundleIdentifier!) if (FileManager.default.fileExists(atPath: path!) == false) { try?FileManager.default.createDirectory(atPath: path!, withIntermediateDirectories: false) } path?.append("/") path?.append("convert.pdf") return path! } @IBAction func buttonClicked_MoreConvert(_ sender: NSButton) { if sender == self.moreButton { FMTrackEventManager.defaultManager.trackEvent(event: "PUW", withProperties: ["PUW_Btn": "Btn_PUW_Converter_Premium_UnlimitedConvertw"]) } else if sender == self.upgradeButton { FMTrackEventManager.defaultManager.trackEvent(event: "PUW", withProperties: ["PUW_Btn": "Btn_PUW_Converter_Premium_Upgrade"]) } #if VERSION_DMG if IAPProductsManager.default().isAvailableAllFunction() && !IAPProductsManager.default().isAvailableAdvancedPDFToOffice() { let limitWC = KMPurchaseLimitWindowController.currentLimitWC() limitWC.continueBlock = { windowController in } limitWC.window?.center() limitWC.showWindow(nil) } else { let winC = KMPurchaseCompareWindowController.sharedInstance() if convertType == .Word || convertType == .AdvancedWord { winC?.kEventName = "Reading_PDFtoWord_BuyNow" } else if convertType == .Excel { winC?.kEventName = "Reading_PDFtoExcel_BuyNow" } else if convertType == .PPT { winC?.kEventName = "Reading_PDFtoPPT_BuyNow" } else if convertType == .RTF { winC?.kEventName = "Reading_PDFtoRTF_BuyNow" } else if convertType == .CSV { winC?.kEventName = "Reading_PDFtoCSV_BuyNow" } else if convertType == .Text { winC?.kEventName = "Reading_PDFtoText_BuyNow" } if convertType == .JPEG || convertType == .JPG || convertType == .PNG || convertType == .GIF || convertType == .TIFF || convertType == .TGA || convertType == .BMP || convertType == .JP2 { winC?.kEventName = "Reading_PDFtoImage_BuyNow" } // else if convertType == . { // winC?.kEventName = "Reading_PDFtoExcel_BuyNow" // } winC?.showWindow(nil) } #else if IAPProductsManager.default().isAvailableAllFunction() { var vc: KMToolCompareWindowController? = nil if convertType == .Word || convertType == .AdvancedWord { // vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 1) vc = KMToolCompareWindowController.toolCompare(toolType: .Convert, selectNum: 1) } else if convertType == .Excel { // vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 2) vc = KMToolCompareWindowController.toolCompare(toolType: .Convert, selectNum: 2) } else if convertType == .PPT { // vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 3) vc = KMToolCompareWindowController.toolCompare(toolType: .Convert, selectNum: 3) } else if convertType.rawValue < 15 && convertType.rawValue > 7 { // vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 4) vc = KMToolCompareWindowController.toolCompare(toolType: .Convert, selectNum: 4) } else { // vc = KMToolCompareWindowController(toolType: .Convert, selectNum: 0) vc = KMToolCompareWindowController.toolCompare(toolType: .Convert, selectNum: 0) } vc?.showWindow(nil) } else { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) } #endif self.buttonClicked_Cancel(self.cancelButton) } @IBAction func buttonItemClick_SepSingle(_ sender: Any) { if .on == self.singleButton.state { self.isAllInOneSheet = true } else { self.isAllInOneSheet = false } } func controlTextDidEndEditing(_ obj: Notification) { let object = obj.object if (object as AnyObject).isEqual(self.currentPageIndexTextField) == true { let num: Int = Int(self.currentPageIndexTextField.stringValue) ?? 1 let targetPage = self.prePDFView.document.page(at: UInt(num - 1)) self.prePDFView.go(to: targetPage) } else if (object as AnyObject).isEqual(self.pageRangeBox) == true { // guard self.handInputButton.state == .on else { return } let idx = self.pageRangeBox.indexOfSelectedItem if idx >= 0 && idx <= 3 { // 0 1 2 3 return } else { // if self.pageRangeBox.indexOfSelectedItem != 4 { // 页面范围切换中 } if self.fileAttri_ == nil { self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = self.pdfDocument?.documentURL.path ?? "" } // fileAttribute.pdfDocument = self.pdfDocument self.fileAttri_?.bAllPage = false self.fileAttri_?.pagesType = .custom self.fileAttri_?.pagesString = self.pageRangeBox.stringValue let pages = self.fileAttri_?.fetchSelectPages() ?? [] if pages.count > 0 { let pagesArray = NSMutableArray() for pageNum in pages { let tpage = self.pdfDocument?.page(at: UInt(pageNum - 1)) pagesArray.add(tpage as Any) } self.produceNewPDF(with: pagesArray as! [CPDFPage]) } else { self.showCriticalAlert(nil) } } } func controlTextDidChange(_ obj: Notification) { if let textField = obj.object as? NSComboBox { if textField.isEqual(pageRangeBox) { if let stringValue = self.currentPageIndexTextField.formatter?.string(for: NSNumber(value: Float(self.currentPageIndexTextField.stringValue) ?? 0)) { if let integerValue = Int(stringValue) { var string = stringValue if integerValue > self.prePDFView.document.pageCount { string = "1-\(self.prePDFView.document.pageCount)" } else if integerValue <= 0 { string = "1" } self.currentPageIndexTextField.stringValue = string } } } } } @IBAction func comboxClicked_PageRange(_ sender: NSComboBox) { if (0 == pageRangeBox.indexOfSelectedItem || 1 == pageRangeBox.indexOfSelectedItem || 2 == pageRangeBox.indexOfSelectedItem || 3 == pageRangeBox.indexOfSelectedItem) { self.window?.makeFirstResponder(self) pageRangeBox.isEditable = false pageRangeBox.delegate = nil } else { pageRangeBox.stringValue = pageRangeBox.stringValue pageRangeBox.isEditable = true pageRangeBox.delegate = self self.window?.makeFirstResponder(pageRangeBox) } self.lockPassword = "" let pagesArray = NSMutableArray() for i in 0..<(self.pdfDocument?.pageCount ?? 0) { let copyPage = self.pdfDocument?.page(at: i) pagesArray.add(copyPage!) } if (2 == pageRangeBox.indexOfSelectedItem) { pagesArray.subArray(type: .Odd) produceNewPDF(with: pagesArray as! [CPDFPage]) } else if (3 == pageRangeBox.indexOfSelectedItem) { pagesArray.subArray(type: .Even) produceNewPDF(with: pagesArray as! [CPDFPage]) } else if (1 == pageRangeBox.indexOfSelectedItem) { pagesArray.removeAllObjects() let page = self.prePDFView.currentPage() if (page != nil) { pagesArray.add(page as Any) } produceNewPDF(with: pagesArray as! [CPDFPage]) } } @IBAction func comboxClicked_OcrLanguage(_ sender: AnyObject?) { switch (ocrLanguageBox.indexOfSelectedItem) { case 0: //chinese self.ocrLanguage_ = .chinese break case 1: //chinese zht self.ocrLanguage_ = .chineseTraditional break case 2: //English self.ocrLanguage_ = .english break case 3: //Japanese self.ocrLanguage_ = .japanese break case 4: //Kroean self.ocrLanguage_ = .korean break case 5: //Serbian self.ocrLanguage_ = .serbian break case 6: //Occitan self.ocrLanguage_ = .occitan break case 7: //Danish self.ocrLanguage_ = .danish break case 8: //German self.ocrLanguage_ = .german break case 9: //French self.ocrLanguage_ = .french break case 10: //Italian self.ocrLanguage_ = .italian break case 11: //Spanish self.ocrLanguage_ = .spanish break case 12: //Portuguese self.ocrLanguage_ = .portuguese break case 13: //Maori self.ocrLanguage_ = .maori break case 14: //Malay self.ocrLanguage_ = .malay break case 15: //Malay self.ocrLanguage_ = .maltese break case 16: //Dutch self.ocrLanguage_ = .dutch break case 17: //Norwegian self.ocrLanguage_ = .norwegian break case 18: //Polish self.ocrLanguage_ = .polish break case 19: //Romanian self.ocrLanguage_ = .romanian break case 20: //Slovak self.ocrLanguage_ = .slovak break case 21: //Slovenian self.ocrLanguage_ = .slovenian break case 22: //Albanian self.ocrLanguage_ = .albanian break case 23: //Swedish self.ocrLanguage_ = .swedish break case 24: //Swahili self.ocrLanguage_ = .swahili break case 25: //Tagalog self.ocrLanguage_ = .tagalog break case 26: //Turish self.ocrLanguage_ = .turish break case 27: //Uzbek self.ocrLanguage_ = .uzbek break case 28: //Vietnamese self.ocrLanguage_ = .vietnamese break case 29: //Afrikaans self.ocrLanguage_ = .afrikaans break case 30: //Azerbaijani self.ocrLanguage_ = .azerbaijani break case 31: //Bosnian self.ocrLanguage_ = .bosnian break case 32: //Czech self.ocrLanguage_ = .czech break case 33: //Welsh self.ocrLanguage_ = .welsh break case 34: //Estonian self.ocrLanguage_ = .estonian break case 35: //Irish self.ocrLanguage_ = .irish break case 36: //Croatian self.ocrLanguage_ = .croatian break case 37: //Hungarian self.ocrLanguage_ = .hungarian break case 38: //Indonesian self.ocrLanguage_ = .indonesian break case 39: //Icelandic self.ocrLanguage_ = .icelandic break case 40: //Kurdish self.ocrLanguage_ = .kurdish break case 41: //Lithuanian self.ocrLanguage_ = .lithuanian break case 42: //Latvian self.ocrLanguage_ = .latvian break case 43: //Marathi self.ocrLanguage_ = .marathi break case 44: //Nepali self.ocrLanguage_ = .nepali break case 45: //Latvia self.ocrLanguage_ = .latvian break case 46: //Bihari self.ocrLanguage_ = .bihari break case 47: //Maithili self.ocrLanguage_ = .maithili break case 48: //Angika self.ocrLanguage_ = .angika break case 49: //Bhojpuri self.ocrLanguage_ = .bhojpuri break case 50: //Magahi self.ocrLanguage_ = .magahi break case 51: //Nagpur self.ocrLanguage_ = .nagpur break case 52: //Newari self.ocrLanguage_ = .newari break case 53: //GoanKonkani self.ocrLanguage_ = .goanKonkani break case 54: //SaudiArabia self.ocrLanguage_ = .saudiArabia break default: self.ocrLanguage_ = .english break } } @IBAction func comboxClicked_SupoortOCR(_ sender: AnyObject?) { if(ocrButton.state == .on) { ocrLabel.textColor = KMAppearance.titleColor() ocrLanguageBox.isEnabled = true } else { ocrLabel.textColor = KMAppearance.Layout.h2Color() ocrLanguageBox.isEnabled = false } } } @objc enum KMSubArrayType: Int { case Odd = 0 case Even } extension NSMutableArray{ func subArray(type: KMSubArrayType) { if self.count == 0 { return } if type.rawValue > 1 || type.rawValue < 0 { return } let newArray = NSMutableArray() for i in 0..