KMURLToPDFWindowController.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. //
  2. // KMURLToPDFWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2023/1/29.
  6. //
  7. import Cocoa
  8. let kUrlToPDFFolderPath = (try? FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(Bundle.main.bundleIdentifier ?? "").appendingPathComponent("WebPage"))?.path ?? ""
  9. typealias KMURLToPDFWindowControllerComplete = (_ filePath: String) -> Void
  10. class KMURLToPDFWindowController: NSWindowController, NSTextFieldDelegate {
  11. @IBOutlet var urlBtn: NSButton!
  12. @IBOutlet var localHtmlBtn: NSButton!
  13. @IBOutlet var outputBackView: NSView!
  14. @IBOutlet var outputText: NSTextField!
  15. @IBOutlet var outputButton: NSButton!
  16. @IBOutlet var pageSizeComboBox: NSComboBox!
  17. @IBOutlet var pageViewLabel: NSTextField!
  18. @IBOutlet var pageSizeLabel: NSTextField!
  19. @IBOutlet var pageGapLabel: NSTextField!
  20. @IBOutlet var pageGapTextField: NSTextField!
  21. @IBOutlet var pagesGapStepper: NSStepper!
  22. @IBOutlet var btnConvert: NSButton!
  23. @IBOutlet var btnCancel: NSButton!
  24. @IBOutlet var urlTextField: NSTextField!
  25. var filePath: String?
  26. var posterMaskView: KMBookletMaskView?
  27. var gap: CGFloat = 0
  28. var pageSize: CGSize = CGSizeMake(298, 420)
  29. var handler: KMURLToPDFWindowControllerComplete?
  30. override init(window: NSWindow?) {
  31. super.init(window: window)
  32. }
  33. required init?(coder: NSCoder) {
  34. super.init(coder: coder)
  35. }
  36. override func windowDidLoad() {
  37. super.windowDidLoad()
  38. window?.title = NSLocalizedString("Web Page To PDF", comment: "")
  39. pageViewLabel.stringValue = NSLocalizedString("Page View", comment: "")
  40. pageSizeLabel.stringValue = NSLocalizedString("Page size:", comment: "")
  41. pageGapLabel.stringValue = "\(NSLocalizedString("Spacing", comment: "")):"
  42. urlBtn.title = NSLocalizedString("URL", comment: "")
  43. localHtmlBtn.title = NSLocalizedString("File", comment: "")
  44. btnConvert.title = NSLocalizedString("Save as PDF", comment: "")
  45. btnCancel.title = NSLocalizedString("Cancel", comment: "")
  46. outputButton.title = NSLocalizedString("Choose...", comment: "")
  47. outputBackView.wantsLayer = true
  48. outputBackView.layer?.borderWidth = 0.8
  49. outputBackView.layer?.borderColor = NSColor(red: 177.0/255, green: 178.0/255, blue: 177.0/255, alpha: 1).cgColor
  50. urlTextField.placeholderString = "https://www.pdfreaderpro.com"
  51. urlTextField.delegate = self
  52. outputText.isEditable = false
  53. pageSizeComboBox.addItems(withObjectValues: [
  54. NSLocalizedString("Automatically Resize", comment: "Menu item title"),
  55. "4A0 1682 × 2378 mm",
  56. "2A0 1189 × 1682 mm",
  57. "A0 841 × 1189 mm",
  58. "A1 594 × 841 mm",
  59. "A2 420 × 594 mm",
  60. "A3 297 × 420 mm",
  61. "A4 210 × 297 mm",
  62. "A5 148 × 210 mm",
  63. "A6 105 × 148 mm",
  64. "A7 74 × 105 mm",
  65. "A8 52 × 74 mm",
  66. "A9 37 × 52 mm",
  67. "A10 26 × 37 mm"
  68. ])
  69. pageSizeComboBox.selectItem(at: 0)
  70. pageSizeComboBox.isEditable = false
  71. pageSize = CGSizeMake(298, 420)
  72. gap = 0
  73. pagesGapStepper.stringValue = "0"
  74. pagesGapStepper.isEnabled = false
  75. pageGapTextField.isEnabled = false
  76. if urlBtn.state == .on {
  77. if urlTextField.stringValue.count > 0 {
  78. btnConvert.isEnabled = true
  79. } else {
  80. btnConvert.isEnabled = false
  81. }
  82. } else {
  83. if outputText.stringValue.count > 0 {
  84. btnConvert.isEnabled = true
  85. } else {
  86. btnConvert.isEnabled = false
  87. }
  88. }
  89. outputText.placeholderString = "\(NSLocalizedString("Select a File", comment: "")) (.html, .webarchive)"
  90. outputButton.isEnabled = false
  91. }
  92. func isUrl(_ urlString: String?) -> Bool {
  93. guard let urlString = urlString else { return false }
  94. // 实现方法有问题,暂不使用
  95. var url: String
  96. if urlString.count > 4, urlString.prefix(4) == "www." {
  97. url = "http://\(urlString)"
  98. } else {
  99. url = urlString
  100. }
  101. let urlRegex = "\\bhttps?://[a-zA-Z0-9\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?"
  102. let urlTest = NSPredicate(format: "SELF MATCHES %@", urlRegex)
  103. return urlTest.evaluate(with: url)
  104. }
  105. func beginSheetModalForWindow(_ window: NSWindow, completionHandler handler: ((String) -> Void)?) {
  106. self.handler = handler
  107. NSWindow.currentWindow().beginSheet(self.window!) { response in
  108. self.handler?(self.filePath ?? "")
  109. }
  110. }
  111. @IBAction func buttonItemClicked_Cancel(_ sender: NSButton) {
  112. NSWindow.currentWindow().endSheet(self.window!)
  113. self.window?.orderOut(self)
  114. }
  115. func urlValueEncode(_ str: String) -> String? {
  116. let allowedCharacterSet = CharacterSet(charactersIn: "!*'();:@&=+$,?%#[]{}").inverted
  117. return str.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
  118. }
  119. @IBAction func buttonItemClicked_Start(_ sender: NSButton) {
  120. if !FileManager.default.fileExists(atPath: kUrlToPDFFolderPath) {
  121. try? FileManager.default.createDirectory(atPath: kUrlToPDFFolderPath, withIntermediateDirectories: false, attributes: nil)
  122. }
  123. var url: URL?
  124. var fileName: String?
  125. if urlBtn.state == .on {
  126. let urlString = urlTextField.stringValue
  127. var tUrl = URL(string: urlString)
  128. if tUrl?.scheme?.count ?? 0 < 1 {
  129. tUrl = URL(string: "http://\(urlString)")
  130. }
  131. url = tUrl
  132. } else {
  133. url = URL(fileURLWithPath: outputText.stringValue)
  134. fileName = outputText.stringValue.deletingPathExtension.lastPathComponent
  135. }
  136. let string = pageGapTextField.stringValue
  137. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  138. if string.stringToCGFloat() <= 0 {
  139. pageGapTextField.stringValue = "0"
  140. } else if string.stringToCGFloat() * unitScale > pageSize.width / 2 {
  141. let maxF = pageSize.width / (string.stringToCGFloat() * 2)
  142. pageGapTextField.stringValue = "\(maxF)"
  143. }
  144. gap = formatFloat(Float(string.stringToCGFloat() * unitScale)).stringToCGFloat()
  145. if let url = url {
  146. showWaitting()
  147. let convert = KMConvertURLToPDF.shareInstance()
  148. convert.fileName = fileName ?? ""
  149. convert.convertUrl(toPDF: [url], toPath: kUrlToPDFFolderPath, pageSize: pageSize, gap: gap, progress: { value in
  150. // Progress update
  151. }, completionHandler: { successArray, failArray in
  152. self.hideWaitting()
  153. if failArray.isEmpty {
  154. if let filePath = successArray.first as? String, FileManager.default.fileExists(atPath: filePath) {
  155. self.filePath = filePath
  156. NSApp.endSheet(self.window!, returnCode: sender.tag)
  157. self.window?.orderOut(self)
  158. }
  159. } else {
  160. let alert = NSAlert()
  161. alert.alertStyle = .critical
  162. alert.informativeText = NSLocalizedString("Conversion Failed", comment: "")
  163. alert.messageText = ""
  164. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  165. alert.runModal()
  166. }
  167. })
  168. }
  169. }
  170. @IBAction func buttonItemClick_Add(_ sender: Any) {
  171. urlBtn.state = .off
  172. localHtmlBtn.state = .on
  173. urlTextField.isEditable = false
  174. urlTextField.stringValue = ""
  175. btnConvert.isEnabled = false
  176. let panel = NSOpenPanel()
  177. panel.canChooseFiles = true
  178. panel.canChooseDirectories = false
  179. panel.allowsMultipleSelection = false
  180. panel.allowedFileTypes = ["HTML", "html", "webarchive", "htm"]
  181. panel.beginSheetModal(for: window!) { response in
  182. if response == .OK {
  183. self.outputText.stringValue = panel.url?.path ?? ""
  184. self.btnConvert.isEnabled = true
  185. }
  186. }
  187. }
  188. @IBAction func buttonItemClick_ChangeType(_ sender: NSButton) {
  189. if urlBtn.state == .on {
  190. urlTextField.isEditable = true
  191. urlTextField.becomeFirstResponder()
  192. outputText.stringValue = ""
  193. outputButton.isEnabled = false
  194. if urlTextField.stringValue.count > 0 {
  195. btnConvert.isEnabled = true
  196. } else {
  197. btnConvert.isEnabled = false
  198. }
  199. } else {
  200. urlTextField.isEditable = false
  201. urlTextField.stringValue = ""
  202. outputButton.isEnabled = true
  203. if outputText.stringValue.count > 0 {
  204. btnConvert.isEnabled = true
  205. } else {
  206. btnConvert.isEnabled = false
  207. }
  208. }
  209. }
  210. @IBAction func comboBoxItemClick_PageSize(_ sender: NSComboBox) {
  211. switch sender.indexOfSelectedItem {
  212. case 0:
  213. pageSize = CGSizeMake(298, 420)
  214. case 1:
  215. pageSize = CGSize(width: 4760, height: 6736)
  216. case 2:
  217. pageSize = CGSize(width: 3368, height: 4760)
  218. case 3:
  219. pageSize = CGSize(width: 2380, height: 3368)
  220. case 4:
  221. pageSize = CGSize(width: 1684, height: 2380)
  222. case 5:
  223. pageSize = CGSize(width: 1190, height: 1684)
  224. case 6:
  225. pageSize = CGSize(width: 842, height: 1190)
  226. case 7:
  227. pageSize = CGSize(width: 595, height: 842)
  228. case 8:
  229. pageSize = CGSize(width: 420, height: 595)
  230. case 9:
  231. pageSize = CGSize(width: 297, height: 420)
  232. default:
  233. pageSize = CGSize(width: 210, height: 297)
  234. }
  235. if sender.indexOfSelectedItem != 0 {
  236. pagesGapStepper.stringValue = "0"
  237. pageGapTextField.stringValue = "0"
  238. pageGapTextField.isEnabled = true
  239. pagesGapStepper.isEnabled = true
  240. } else {
  241. pagesGapStepper.stringValue = "0"
  242. pageGapTextField.stringValue = ""
  243. pageGapTextField.isEnabled = false
  244. pagesGapStepper.isEnabled = false
  245. }
  246. }
  247. @IBAction func stepperItemClick_Gap(_ sender: NSStepper) {
  248. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  249. pageGapTextField.stringValue = String(format: "%.2f", pagesGapStepper.floatValue)
  250. gap = formatFloat(pagesGapStepper.floatValue * Float(unitScale)).stringToCGFloat()
  251. }
  252. func controlTextDidEndEditing(_ obj: Notification) {
  253. if let object = obj.object as? NSTextField, object == pageGapTextField {
  254. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  255. if object.stringValue.stringToCGFloat() <= 0 {
  256. pageGapTextField.stringValue = "0"
  257. } else if object.stringValue.stringToCGFloat() * unitScale > pageSize.width / 2 {
  258. let maxF = pageSize.width / (object.stringValue.stringToCGFloat() * 2)
  259. pageGapTextField.stringValue = "\(maxF)"
  260. }
  261. gap = formatFloat(Float(object.stringValue.stringToCGFloat() * unitScale)).stringToCGFloat()
  262. pagesGapStepper.floatValue = Float(object.stringValue.stringToCGFloat())
  263. }
  264. }
  265. func controlTextDidChange(_ notification: Notification) {
  266. if urlBtn.state == .on {
  267. if urlTextField.stringValue.count > 0 {
  268. btnConvert.isEnabled = true
  269. } else {
  270. btnConvert.isEnabled = false
  271. }
  272. } else {
  273. if outputText.stringValue.count > 0 {
  274. btnConvert.isEnabled = true
  275. } else {
  276. btnConvert.isEnabled = false
  277. }
  278. }
  279. }
  280. func formatFloat(_ f: Float) -> String {
  281. if f.truncatingRemainder(dividingBy: 1) == 0 {
  282. return String(format: "%.0f", f)
  283. } else if (f * 10).truncatingRemainder(dividingBy: 1) == 0 {
  284. return String(format: "%.1f", f)
  285. } else {
  286. return String(format: "%.2f", f)
  287. }
  288. }
  289. func showWaitting() {
  290. if posterMaskView == nil {
  291. posterMaskView = KMBookletMaskView(frame: NSMakeRect(0, 0, window?.frame.size.width ?? 0, window?.frame.size.height ?? 0))
  292. }
  293. window?.contentView?.addSubview(posterMaskView!)
  294. }
  295. func hideWaitting() {
  296. posterMaskView?.removeFromSuperview()
  297. }
  298. }