KMDocumentController.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // KMDocumentController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2022/12/5.
  6. //
  7. import Cocoa
  8. let KMPDFDocumentType: String = "com.adobe.pdf"
  9. let KMPDFBundleDocumentType: String = "net.sourceforge.skim-app.pdfd"
  10. let KMNotesDocumentType: String = "net.sourceforge.skim-app.skimnotes"
  11. let KMNotesTextDocumentType: String = "public.plain-text"
  12. let KMNotesRTFDocumentType: String = "public.rtf"
  13. let KMNotesRTFDDocumentType: String = "com.apple.rtfd"
  14. let KMNotesFDFDocumentType: String = "com.adobe.fdf"
  15. let KMPostScriptDocumentType: String = "com.adobe.postscript"
  16. let KMEncapsulatedPostScriptDocumentType: String = "com.adobe.encapsulated-postscript"
  17. let KMDVIDocumentType: String = "org.tug.tex.dvi"
  18. let KMXDVDocumentType: String = "org.tug.tex.xdv"
  19. let KMFolderDocumentType: String = "public.folder"
  20. let KMDocumentSetupAliasKey: String = "_BDAlias"
  21. let KMDocumentSetupFileNameKey: String = "fileName"
  22. class KMDocumentController: NSDocumentController {
  23. func fetchUniquePath(_ originalPath: String) -> String {
  24. var path = originalPath
  25. let dManager = FileManager.default
  26. if !dManager.fileExists(atPath: path) {
  27. if path.extension.count < 1 {
  28. path = path.stringByAppendingPathExtension("pdf")
  29. }
  30. return path
  31. } else {
  32. let originalFullFileName = path.lastPathComponent
  33. let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent
  34. let originalExtension = path.extension
  35. let startIndex: Int = 0
  36. let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1
  37. let fileLocatePath = originalPath.substring(to: endIndex)
  38. var i = 1
  39. while (1 != 0) {
  40. var newName = String(format: "%@%ld", originalFileName, i)
  41. newName = String(format: "%@%@", newName, originalExtension)
  42. let newPath = fileLocatePath.stringByAppendingPathComponent(newName)
  43. if !dManager.fileExists(atPath: newPath) {
  44. return newPath
  45. } else {
  46. i+=1
  47. continue
  48. }
  49. }
  50. }
  51. }
  52. func kNewDocumentTempSavePath(_ fileName: String) -> String {
  53. let searchPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last
  54. let append1 = searchPath?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!)
  55. let append2 = append1!.stringByAppendingPathComponent(String(format: "%@", fileName))
  56. return append2
  57. }
  58. func savePdf(_ filePath: String) -> Void {
  59. let pdfData = try! Data(contentsOf: URL(fileURLWithPath: filePath))
  60. let document = try! self.makeUntitledDocument(ofType: KMPDFDocumentType) as NSDocument
  61. if ((try? document.read(from: pdfData, ofType: KMPDFDocumentType)) != nil) {
  62. self.addDocument(document)
  63. document.makeWindowControllers()
  64. document.showWindows()
  65. }
  66. }
  67. // MARK: Action
  68. @IBAction func importFromFile(_ sender: Any) {
  69. }
  70. @IBAction func openBlankPage(_ sender: Any) {
  71. let fileName = String(format: "%@.pdf", NSLocalizedString("Untitled", comment: ""))
  72. let savePath = fetchUniquePath(kNewDocumentTempSavePath(fileName))
  73. let pdfDocument = CPDFDocument()
  74. pdfDocument?.insertPage(CGSize(width: 595, height: 842), at: 0)
  75. pdfDocument?.write(to: URL(fileURLWithPath: savePath))
  76. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePath), display: true) { document, documentWasAlreadyOpen, error in
  77. if error != nil {
  78. NSApp.presentError(error!)
  79. return
  80. }
  81. if document is KMMainDocument {
  82. let newDocument = document
  83. (newDocument as! KMMainDocument).isNewCreated = false
  84. }
  85. }
  86. }
  87. @IBAction func newDocumentFromImage(_ sender: Any) {
  88. // let openPanel = NSOpenPanel()
  89. // openPanel.allowedFileTypes = KMImageAccessoryController.supportedImageTypes()
  90. // openPanel.allowsMultipleSelection = true
  91. // openPanel.message = NSLocalizedString("Select images to create a new document. To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "")
  92. // openPanel.beginSheetModal(for: NSApp.mainWindow!) { response in
  93. // let savePath = self.kNewDocumentTempSavePath("convertToPDF.pdf")
  94. // if response == .OK {
  95. // KMConvertPDFManager.convertImages(openPanel.urls, savePath: savePath) { success, errorDic in
  96. // if !success || !FileManager.default.fileExists(atPath: savePath) {
  97. // if FileManager.default.fileExists(atPath: savePath) {
  98. // try? FileManager.default.removeItem(atPath: savePath)
  99. // }
  100. //
  101. // let alert = NSAlert()
  102. // alert.alertStyle = .critical
  103. // alert.messageText = NSLocalizedString("Conversion Failed", comment: "")
  104. // alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  105. // alert.runModal()
  106. // return
  107. // }
  108. // self.savePdf(savePath)
  109. // try? FileManager.default.removeItem(atPath: savePath)
  110. // }
  111. // }
  112. // }
  113. }
  114. @IBAction func importFromWebPage(_ sender: Any) {
  115. let windowController: KMURLToPDFWindowController = KMURLToPDFWindowController.init(windowNibName: NSNib.Name("KMURLToPDFWindowController"))
  116. windowController.beginSheetModalForWindow(NSWindow.currentWindow()) { filePath in
  117. if FileManager.default.fileExists(atPath: filePath) {
  118. NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: filePath), display: true) { document, documentWasAlreadyOpen, error in
  119. if error != nil {
  120. NSApp.presentError(error!)
  121. return
  122. }
  123. if document is KMMainDocument {
  124. (document as! KMMainDocument).isNewCreated = true
  125. }
  126. }
  127. }
  128. }
  129. }
  130. @IBAction func importFromScanner(_ sender: Any) {
  131. }
  132. }
  133. extension NSDocumentController {
  134. func openDocumentWithURLFromPasteboard(_ pboard: NSPasteboard, showNotes: Bool, outError: NSErrorPointer) -> Any? {
  135. guard let theURLs = NSURL.readURLs(from: pboard), let theURL = theURLs.first else {
  136. if showNotes == false {
  137. outError?.pointee = NSError.readPasteboardError(withLocalizedDescription: NSLocalizedString("Unable to load data from clipboard", comment: "Error description"))
  138. }
  139. return nil
  140. }
  141. // guard (theURL as AnyObject).isFileURL else {
  142. // if showNotes == false {
  143. // return SKDownloadController.shared.addDownload(for: theURL)
  144. // }
  145. // return nil
  146. // }
  147. var document: Any?
  148. do {
  149. let type = try self.typeForContents(of: theURL as! URL)
  150. // if showNotes == false || KMNotesDocument.readableTypes.contains(type) {
  151. // document = try self.openDocument(withContentsOf: theURL as! URL, display: true)
  152. // } else
  153. if KMMainDocument.readableTypes.contains(type) {
  154. for doc in self.documents {
  155. if let sourceURL = (doc as? NSObject)?.value(forKey: "sourceFileURL") as? URL, sourceURL == theURL as! URL {
  156. document = doc
  157. break
  158. }
  159. }
  160. if let existingDoc = document as? NSDocument {
  161. existingDoc.showWindows()
  162. } else {
  163. var error: NSError?
  164. var data: Data?
  165. if NSWorkspace.shared.type(type, conformsToType: KMPDFBundleDocumentType) {
  166. let skimFileURL = try self.bundledFileURLWithExtension("skim", inPDFBundleAtURL: theURL as! URL)
  167. data = try Data(contentsOf: skimFileURL)
  168. }
  169. // else {
  170. // data = try SKNExtendedAttributeManager.shared().extendedAttributeNamed(SKIM_NOTES_KEY, atPath: theURL.path, traverseLink: true)
  171. // }
  172. // let newDocument = try makeUntitledDocument(ofType: KMNotesDocumentType)
  173. // newDocument.sourceFileURL = theURL
  174. //
  175. // if data == nil || newDocument.read(from: data ?? Data(), ofType: KMNotesDocumentType) {
  176. // self.addDocument(newDocument)
  177. // newDocument.makeWindowControllers()
  178. // newDocument.showWindows()
  179. // } else {
  180. // document = nil
  181. // outError?.pointee = error
  182. // }
  183. }
  184. }
  185. } catch {
  186. outError?.pointee = error as NSError
  187. }
  188. return document
  189. }
  190. func bundledFileURLWithExtension(_ extension: String, inPDFBundleAtURL theURL: URL) throws -> URL {
  191. let bundleContents = try FileManager.default.contentsOfDirectory(at: theURL, includingPropertiesForKeys: nil, options: [])
  192. for fileURL in bundleContents {
  193. if fileURL.pathExtension == `extension` {
  194. return fileURL
  195. }
  196. }
  197. throw NSError(domain: "YourDomain", code: 404, userInfo: [NSLocalizedDescriptionKey: "File with extension not found in PDF bundle"])
  198. }
  199. func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: NSErrorPointer) -> Any? {
  200. var document: NSDocument?
  201. var data: Data?
  202. var type: String?
  203. if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) {
  204. pboard.types
  205. data = pboard.data(forType: NSPasteboard.PasteboardType.pdf)
  206. type = KMPDFDocumentType
  207. } else if pboard.canReadItem(withDataConformingToTypes: [KMEncapsulatedPostScriptDocumentType]) {
  208. pboard.types
  209. data = pboard.data(forType: NSPasteboard.PasteboardType(rawValue: KMEncapsulatedPostScriptDocumentType))
  210. type = isEncapsulatedPostScriptData(data!) ? KMEncapsulatedPostScriptDocumentType : KMPostScriptDocumentType
  211. } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) {
  212. pboard.types
  213. data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff)!)
  214. type = KMPDFDocumentType
  215. } else {
  216. let images = pboard.readObjects(forClasses: [NSImage.self], options: [:]) as? [NSImage]
  217. let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:]) as? [NSAttributedString]
  218. if let images = images, images.count > 0 {
  219. data = convertTIFFDataToPDF(images[0].tiffRepresentation!)
  220. type = KMPDFDocumentType
  221. } else if let strings = strings, strings.count > 0 {
  222. data = KMOCTool.convertStringsToPDF(withString: strings) // convertStringsToPDF(strings!)
  223. type = KMPDFDocumentType
  224. }
  225. }
  226. if let data = data, let type = type {
  227. var error: NSError?
  228. document = try?makeUntitledDocument(ofType: type)
  229. if ((try?document?.read(from: data, ofType:type)) != nil) {
  230. addDocument(document!)
  231. document?.makeWindowControllers()
  232. document?.showWindows()
  233. } else {
  234. document = nil
  235. if let outError = outError {
  236. outError.pointee = error
  237. }
  238. }
  239. } else if let outError = outError {
  240. outError.pointee = NSError.readPasteboardError(withLocalizedDescription: NSLocalizedString("Unable to load data from clipboard", comment: "Error description"))
  241. }
  242. return document
  243. }
  244. func isEncapsulatedPostScriptData(_ data: Data) -> Bool {
  245. let epsHeaderData = Data(bytes: [69, 80, 83, 70, 45], count: 5)
  246. let rg: Range = (14..<20)
  247. return (data.count >= 20 && (data.range(of: epsHeaderData, options: .anchored, in: rg) != nil))
  248. }
  249. func convertTIFFDataToPDF(_ tiffData: Data) -> Data? {
  250. guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil }
  251. let pdfData = NSMutableData(capacity: tiffData.count)
  252. let consumer = CGDataConsumer(data: pdfData! as CFMutableData)!
  253. var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))
  254. let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil)
  255. ctxt!.beginPDFPage(nil)
  256. ctxt!.draw(cgImage, in: rect)
  257. ctxt!.endPDFPage()
  258. ctxt!.closePDF()
  259. return pdfData as? Data
  260. }
  261. }