KMURLToPDFWindowController.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // KMURLToPDFWindowController.swift
  3. // PDF Master
  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. self.window?.endSheet(NSWindow.currentWindow())
  113. }
  114. func urlValueEncode(_ str: String) -> String? {
  115. let allowedCharacterSet = CharacterSet(charactersIn: "!*'();:@&=+$,?%#[]{}").inverted
  116. return str.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
  117. }
  118. @IBAction func buttonItemClicked_Start(_ sender: NSButton) {
  119. if !FileManager.default.fileExists(atPath: kUrlToPDFFolderPath) {
  120. try? FileManager.default.createDirectory(atPath: kUrlToPDFFolderPath, withIntermediateDirectories: false, attributes: nil)
  121. }
  122. var url: URL?
  123. var fileName: String?
  124. if urlBtn.state == .on {
  125. let urlString = urlTextField.stringValue
  126. var tUrl = URL(string: urlString)
  127. if tUrl?.scheme?.count ?? 0 < 1 {
  128. tUrl = URL(string: "http://\(urlString)")
  129. }
  130. url = tUrl
  131. } else {
  132. url = URL(fileURLWithPath: outputText.stringValue)
  133. fileName = outputText.stringValue.lastPathComponent.deletingPathExtension
  134. }
  135. let string = pageGapTextField.stringValue
  136. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  137. if string.stringToCGFloat() <= 0 {
  138. pageGapTextField.stringValue = "0"
  139. } else if string.stringToCGFloat() * unitScale > pageSize.width / 2 {
  140. let maxF = pageSize.width / (string.stringToCGFloat() * 2)
  141. pageGapTextField.stringValue = "\(maxF)"
  142. }
  143. gap = formatFloat(Float(string.stringToCGFloat() * unitScale)).stringToCGFloat()
  144. if let url = url {
  145. showWaitting()
  146. let convert = KMConvertURLToPDF.shareInstance()
  147. convert.fileName = fileName ?? ""
  148. convert.convertUrl(toPDF: [url], toPath: kUrlToPDFFolderPath, pageSize: pageSize, gap: gap, progress: { value in
  149. // Progress update
  150. }, completionHandler: { successArray, failArray in
  151. self.hideWaitting()
  152. if failArray.isEmpty {
  153. if let filePath = successArray.first as? String, FileManager.default.fileExists(atPath: filePath) {
  154. self.filePath = filePath
  155. NSApp.endSheet(self.window!, returnCode: sender.tag)
  156. self.window?.orderOut(self)
  157. }
  158. } else {
  159. let alert = NSAlert()
  160. alert.alertStyle = .critical
  161. alert.informativeText = NSLocalizedString("Conversion Failed", comment: "")
  162. alert.messageText = ""
  163. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  164. alert.runModal()
  165. }
  166. })
  167. }
  168. }
  169. @IBAction func buttonItemClick_Add(_ sender: Any) {
  170. urlBtn.state = .off
  171. localHtmlBtn.state = .on
  172. urlTextField.isEditable = false
  173. urlTextField.stringValue = ""
  174. btnConvert.isEnabled = false
  175. let panel = NSOpenPanel()
  176. panel.canChooseFiles = true
  177. panel.canChooseDirectories = false
  178. panel.allowsMultipleSelection = false
  179. panel.allowedFileTypes = ["HTML", "html", "webarchive", "htm"]
  180. panel.beginSheetModal(for: window!) { response in
  181. if response == .OK {
  182. self.outputText.stringValue = panel.url?.path ?? ""
  183. self.btnConvert.isEnabled = true
  184. }
  185. }
  186. }
  187. @IBAction func buttonItemClick_ChangeType(_ sender: NSButton) {
  188. if urlBtn.state == .on {
  189. urlTextField.isEditable = true
  190. urlTextField.becomeFirstResponder()
  191. outputText.stringValue = ""
  192. outputButton.isEnabled = false
  193. if urlTextField.stringValue.count > 0 {
  194. btnConvert.isEnabled = true
  195. } else {
  196. btnConvert.isEnabled = false
  197. }
  198. } else {
  199. urlTextField.isEditable = false
  200. urlTextField.stringValue = ""
  201. outputButton.isEnabled = true
  202. if outputText.stringValue.count > 0 {
  203. btnConvert.isEnabled = true
  204. } else {
  205. btnConvert.isEnabled = false
  206. }
  207. }
  208. }
  209. @IBAction func comboBoxItemClick_PageSize(_ sender: NSComboBox) {
  210. switch sender.indexOfSelectedItem {
  211. case 0:
  212. pageSize = CGSizeMake(298, 420)
  213. case 1:
  214. pageSize = CGSize(width: 4760, height: 6736)
  215. case 2:
  216. pageSize = CGSize(width: 3368, height: 4760)
  217. case 3:
  218. pageSize = CGSize(width: 2380, height: 3368)
  219. case 4:
  220. pageSize = CGSize(width: 1684, height: 2380)
  221. case 5:
  222. pageSize = CGSize(width: 1190, height: 1684)
  223. case 6:
  224. pageSize = CGSize(width: 842, height: 1190)
  225. case 7:
  226. pageSize = CGSize(width: 595, height: 842)
  227. case 8:
  228. pageSize = CGSize(width: 420, height: 595)
  229. case 9:
  230. pageSize = CGSize(width: 297, height: 420)
  231. default:
  232. pageSize = CGSize(width: 210, height: 297)
  233. }
  234. if sender.indexOfSelectedItem != 0 {
  235. pagesGapStepper.stringValue = "0"
  236. pageGapTextField.stringValue = "0"
  237. pageGapTextField.isEnabled = true
  238. pagesGapStepper.isEnabled = true
  239. } else {
  240. pagesGapStepper.stringValue = "0"
  241. pageGapTextField.stringValue = ""
  242. pageGapTextField.isEnabled = false
  243. pagesGapStepper.isEnabled = false
  244. }
  245. }
  246. @IBAction func stepperItemClick_Gap(_ sender: NSStepper) {
  247. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  248. pageGapTextField.stringValue = String(format: "%.2f", pagesGapStepper.floatValue)
  249. gap = formatFloat(pagesGapStepper.floatValue * Float(unitScale)).stringToCGFloat()
  250. }
  251. func controlTextDidEndEditing(_ obj: Notification) {
  252. if let object = obj.object as? NSTextField, object == pageGapTextField {
  253. let unitScale: CGFloat = (595.0 / 21.0) * 2.54
  254. if object.stringValue.stringToCGFloat() <= 0 {
  255. pageGapTextField.stringValue = "0"
  256. } else if object.stringValue.stringToCGFloat() * unitScale > pageSize.width / 2 {
  257. let maxF = pageSize.width / (object.stringValue.stringToCGFloat() * 2)
  258. pageGapTextField.stringValue = "\(maxF)"
  259. }
  260. gap = formatFloat(Float(object.stringValue.stringToCGFloat() * unitScale)).stringToCGFloat()
  261. pagesGapStepper.floatValue = Float(object.stringValue.stringToCGFloat())
  262. }
  263. }
  264. func controlTextDidChange(_ notification: Notification) {
  265. if urlBtn.state == .on {
  266. if urlTextField.stringValue.count > 0 {
  267. btnConvert.isEnabled = true
  268. } else {
  269. btnConvert.isEnabled = false
  270. }
  271. } else {
  272. if outputText.stringValue.count > 0 {
  273. btnConvert.isEnabled = true
  274. } else {
  275. btnConvert.isEnabled = false
  276. }
  277. }
  278. }
  279. func formatFloat(_ f: Float) -> String {
  280. if f.truncatingRemainder(dividingBy: 1) == 0 {
  281. return String(format: "%.0f", f)
  282. } else if (f * 10).truncatingRemainder(dividingBy: 1) == 0 {
  283. return String(format: "%.1f", f)
  284. } else {
  285. return String(format: "%.2f", f)
  286. }
  287. }
  288. func showWaitting() {
  289. // if posterMaskView == nil {
  290. // posterMaskView = KMBookletMaskView(frame: NSMakeRect(0, 0, window?.frame.size.width ?? 0, window?.frame.size.height ?? 0))
  291. // }
  292. // window?.contentView?.addSubview(posterMaskView!)
  293. }
  294. func hideWaitting() {
  295. // /*posterMaskView*/?.removeFromSuperview()
  296. }
  297. }