KMEditPDfHanddler.swift 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831
  1. //
  2. // KMEditPDfHanddler.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2024/6/16.
  6. //
  7. import Cocoa
  8. @objc enum KMRightSideLastState: Int {
  9. case none = 0
  10. case open = 1
  11. case close = 2
  12. }
  13. // EditPDF处理对象
  14. class KMEditPDfHanddler: NSObject {
  15. weak var viewC: KMMainViewController?
  16. static let kRightSideLastStateKey = "KMRightSideLastStateKey"
  17. // 正在新增文本块
  18. var addTextAreaing = false
  19. var fontSizeChanging = false
  20. var textAlignChanging = false
  21. weak var listView: CPDFListView? {
  22. get {
  23. return self.viewC?.listView
  24. }
  25. }
  26. var annotationType: CAnnotationType {
  27. get {
  28. return self.listView?.annotationType ?? .unkown
  29. }
  30. }
  31. weak var rightViewC: KMRightSideViewController? {
  32. get {
  33. return self.viewC?.rightSideViewController
  34. }
  35. }
  36. var subViewType: RightSubViewType {
  37. get {
  38. return self.rightViewC?.subViewType ?? .None
  39. }
  40. }
  41. // var toolMode: CToolMode {
  42. // get {
  43. // return
  44. // }
  45. // }
  46. var isEditImage: Bool {
  47. get {
  48. return self.listView?.isEditImage ?? false
  49. }
  50. }
  51. var isEditing: Bool {
  52. get {
  53. return self.listView?.isEditing() ?? false
  54. }
  55. }
  56. var editingConfig: CPDFEditingConfig? {
  57. get {
  58. return self.listView?.editingConfig()
  59. }
  60. }
  61. var editingAreas: [CPDFEditArea] {
  62. get {
  63. return self.listView?.editingAreas() as? [CPDFEditArea] ?? []
  64. }
  65. }
  66. var editingImageAreas: [CPDFEditImageArea] {
  67. get {
  68. var areas: [CPDFEditImageArea] = []
  69. for area in self.editingAreas {
  70. if let data = area as? CPDFEditImageArea {
  71. areas.append(data)
  72. }
  73. }
  74. return areas
  75. }
  76. }
  77. var editingTextAreas: [CPDFEditTextArea] {
  78. get {
  79. var areas: [CPDFEditTextArea] = []
  80. for area in self.editingAreas {
  81. if let data = area as? CPDFEditTextArea {
  82. areas.append(data)
  83. }
  84. }
  85. return areas
  86. }
  87. }
  88. var rightSideLastState: KMRightSideLastState {
  89. get {
  90. let state = KMDataManager.ud_integer(forKey: Self.kRightSideLastStateKey)
  91. return KMRightSideLastState(rawValue: state) ?? .none
  92. }
  93. set {
  94. KMDataManager.ud_set(newValue.rawValue, forKey: Self.kRightSideLastStateKey)
  95. }
  96. }
  97. private var startPoint_: NSPoint = .zero
  98. func enterEditPDF() {
  99. let cnt = self.viewC?.leftSideViewController.leftView.segmentedControl.selectedSegment ?? UInt8.max
  100. if cnt == 0 {
  101. self.viewC?.search(searchString: "", isCase: false, display: true, needShowAll: false)
  102. self.viewC?.leftSideViewController.showSearchMode("")
  103. }
  104. let toolMode = self.listView?.toolMode ?? .none
  105. if toolMode != .editPDFToolMode { // 退出
  106. self.listView?.updateActiveAnnotations([])
  107. self.listView?.setNeedsDisplayForVisiblePages()
  108. self.listView?.commitEditFormText()
  109. self.listView?.commitEditing()
  110. self.listView?.layoutDocumentView()
  111. KMThumbnailCache.shared.clearCache()
  112. NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "CPDFDocumentPageCountChangedNotification"), object: self.listView?.document)
  113. self.closeRightPane()
  114. self.clearData()
  115. return
  116. }
  117. self._addNotification()
  118. if self.rightSideLastState == .open {
  119. self.openRightPane()
  120. } else {
  121. self.closeRightPane()
  122. }
  123. self.listView?.updateActiveAnnotations([])
  124. self.listView?.setNeedsDisplayForVisiblePages()
  125. self.listView?.commitEditFormText()
  126. self.listView?.annotationType = .editTextImage
  127. // 设置边框颜色
  128. self.editingConfig?.editingBorderColor = .clear
  129. // 设置边框宽度
  130. // self.editingConfig?.editingBorderWidth = 10
  131. // 内容与边框的间距
  132. // self.editingConfig?.editAreaMargin = .init(floatLiteral: 5)
  133. // 设置选中块边框颜色
  134. // self.editingConfig?.editingSelectionBorderColor = .red
  135. // 显示hover边框
  136. self.editingConfig?.isShowMouseAreaHover = true
  137. // hover
  138. // 边框宽度
  139. // self.editingConfig?.mouseHoverBorderWidth = 1
  140. // 边框颜色
  141. self.editingConfig?.mouseHoverBorderColor = NSColor(hex: "#999999")
  142. // 边框虚线设置
  143. self.editingConfig?.mouseHoverBorderDashPattern = [3,3,3]
  144. // 块填充颜色(拖拽中)
  145. // self.editingConfig?.editAreaMoveFillColor = .cyan
  146. // 是否显示位置辅助线
  147. self.editingConfig?.isShowEditingAreaHover = true
  148. // 辅助线颜色
  149. // self.editingConfig?.editingHoverBorderColor = .brown
  150. // 支持多选
  151. self.editingConfig?.isSupportMultipleSelectEditingArea = true
  152. // 图片是否显示8个操作点
  153. self.editingConfig?.isDrawRectWithDot = true
  154. // self.editingConfig?.editingMouseSelectionBorderColor
  155. self.editingConfig?.editingMouseSelectionBorderWidth = 1
  156. self.editingConfig?.editingMouseSelectionBorderDashPattern = [3, 3, 3]
  157. }
  158. func commitEditing() {
  159. let isEdited = self.listView?.isEdited() ?? false
  160. let isPDFTextImageEdited = self.viewC?.model.isPDFTextImageEdited ?? false
  161. if isEdited || isPDFTextImageEdited {
  162. self.viewC?.model.isPDFTextImageEdited = false
  163. self.listView?.commitEditing()
  164. self.listView?.layoutDocumentView()
  165. }
  166. self.clearData()
  167. }
  168. func openRightPane() {
  169. let state = self.rightSideLastState
  170. if state == .none || state == .open {
  171. self.viewC?.openRightPane()
  172. }
  173. }
  174. func closeRightPane() {
  175. self.rightViewC?.isHidden = true
  176. self.viewC?.closeRightPane()
  177. }
  178. func showPopWindow(positionRect: NSRect, showGuide: Bool) {
  179. if self.editAreasIsEmpty() {
  180. return
  181. }
  182. let show = KMPreference.shared.editPDFPopWindowIsShow
  183. if !show {
  184. return
  185. }
  186. let win = KMEditPDFPopToolBarWindow.shared
  187. self._kRemoveChildWindow(win)
  188. let areas = self.editingAreas
  189. win.isMultiple = areas.count > 1
  190. var hasText = false
  191. var hasImage = false
  192. var fontColors: [NSColor] = []
  193. for area in areas {
  194. if let data = area as? CPDFEditTextArea {
  195. hasText = true
  196. if let color = self.listView?.editingSelectionFontColor(with: data) {
  197. fontColors.append(color)
  198. }
  199. }
  200. if area is CPDFEditImageArea {
  201. hasImage = true
  202. }
  203. }
  204. var style: KMEditPDFToolbarStyle = []
  205. if hasText {
  206. style.insert(.text)
  207. }
  208. if hasImage {
  209. style.insert(.image)
  210. }
  211. win.style = style
  212. win.model.editingAreas = areas
  213. win.model.fontColors = fontColors
  214. win.model.fontNames = self._editAreasFontNames()
  215. win.model.fontSizes = self._editAreasFontSizes()
  216. win.model.fontBolds = self._editAreasFontBolds()
  217. win.model.fontItalics = self._editAreasFontItalics()
  218. win.model.textAlignments = self._editAreasTextAlignments()
  219. win.model.rotates = self._editAreasRotates()
  220. win.model.opacitys = self._editAreasOpacitys()
  221. let area = (self.listView?.editingAreas().first as? CPDFEditArea)
  222. var areaBounds = (self.listView?.convert(area!.bounds, from: area!.page) as? NSRect) ?? .zero
  223. var maxX = NSMaxX(areaBounds)
  224. var maxY = NSMaxY(areaBounds)
  225. for area in self.editingAreas {
  226. // let bounds = area.bounds
  227. let bounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  228. areaBounds.origin.x = min(areaBounds.origin.x, bounds.origin.x)
  229. areaBounds.origin.y = min(areaBounds.origin.y, bounds.origin.y)
  230. maxX = max(maxX, NSMaxX(bounds))
  231. areaBounds.size.width = maxX-areaBounds.origin.x
  232. maxY = max(maxY, NSMaxY(bounds))
  233. areaBounds.size.height = maxY-areaBounds.origin.y
  234. }
  235. self.startPoint_ = self.listView?.documentView().documentVisibleRect.origin ?? .zero
  236. win.show(relativeTo: areaBounds, of: self.viewC!.listView, preferredEdge: .maxY)
  237. win.animator().alphaValue = 1
  238. self._kAddchildwindow(win)
  239. win.itemClick = { [weak self] itemKey, obj in
  240. if itemKey == .color {
  241. self?.fontColorAction(color: obj as? NSColor)
  242. } else if itemKey == .fontStyle {
  243. self?.fontStyleAction(fontName: obj as? String)
  244. } else if itemKey == .fontAdd {
  245. self?.fontAddAction()
  246. } else if itemKey == .fontReduce {
  247. self?.fontReduceAction()
  248. } else if itemKey == .fontBold {
  249. self?.fontBoldAction()
  250. } else if itemKey == .fontItalic {
  251. self?.fontItalicAction()
  252. } else if itemKey == .textAlignment {
  253. self?.textAlignmentAction(align: obj as? NSTextAlignment ?? .left)
  254. }
  255. // 图片
  256. else if itemKey == .leftRotate {
  257. self?.leftRotateAction()
  258. } else if itemKey == .rightRotate {
  259. self?.rightRotateAction()
  260. } else if itemKey == .reverseX {
  261. self?.reverseXAction()
  262. } else if itemKey == .reverseY {
  263. self?.reverseYAction()
  264. } else if itemKey == .crop {
  265. self?.cropAction()
  266. } else if itemKey == .replace {
  267. self?.replaceAction()
  268. } else if itemKey == .export {
  269. if let data = obj as? NSView {
  270. self?.showExportMenu(data)
  271. }
  272. }
  273. // 对齐
  274. else if itemKey == .alignmentLeft {
  275. self?.alignmentAction(align: .Left)
  276. } else if itemKey == .alignmentCenterX {
  277. self?.alignmentAction(align: .Horizontally)
  278. } else if itemKey == .alignmentRight {
  279. self?.alignmentAction(align: .Right)
  280. } else if itemKey == .alignmentjustifiedX {
  281. self?.alignmentAction(align: .DisHorizontally)
  282. } else if itemKey == .alignmentTop {
  283. self?.alignmentAction(align: .Top)
  284. } else if itemKey == .alignmentCenterY {
  285. self?.alignmentAction(align: .Vertical)
  286. } else if itemKey == .alignmentBottom {
  287. self?.alignmentAction(align: .Bottom)
  288. } else if itemKey == .alignmentjustifiedY {
  289. self?.alignmentAction(align: .DisVertical)
  290. }
  291. }
  292. // 显示新手引导
  293. if let toolbarView = (win.contentViewController as? KMEditPDFPopToolBarController)?.toolbarView {
  294. if showGuide {
  295. self.showGuideView(toolbarView)
  296. }
  297. }
  298. }
  299. func hiddenPopWindow() {
  300. let win = KMEditPDFPopToolBarWindow.shared
  301. win.orderOut(nil)
  302. win.setIsVisible(false)
  303. self._kRemoveChildWindow(win)
  304. }
  305. func showCropComfirmWindow() {
  306. let winC = KMEditPDFCropComfirmWindowController.shared
  307. if KMEditPDFPopToolBarWindow.shared.isVisible {
  308. let winFrame = KMEditPDFPopToolBarWindow.shared.frame
  309. let x = winFrame.origin.x + (NSWidth(winFrame)-84) * 0.5
  310. let frame = NSMakeRect(x, winFrame.origin.y, 84, 44)
  311. winC.window?.setFrame(frame, display: true)
  312. } else {
  313. let area = (self.listView?.editingAreas().first as? CPDFEditArea)
  314. let areaBounds = (self.listView?.convert(area!.bounds, from: area!.page) as? NSRect) ?? .zero
  315. let positioningView = self.listView
  316. let winFrame = positioningView?.window?.frame ?? .zero
  317. let toView: NSView? = nil
  318. var position = positioningView?.convert(areaBounds.origin, to: toView) ?? .zero
  319. position.x += winFrame.origin.x
  320. position.y += winFrame.origin.y
  321. position.y += areaBounds.size.height
  322. position.y += 26
  323. let x = position.x + (NSWidth(areaBounds)-84) * 0.5
  324. let frame = NSMakeRect(x, position.y, 84, 44)
  325. winC.window?.setFrame(frame, display: true)
  326. }
  327. winC.showWindow(nil)
  328. self._kAddchildwindow(winC.window!)
  329. winC.itemAction = { [weak self] idx, _ in
  330. if idx == 0 { // 确认
  331. self?.cropComfirmAction()
  332. } else if idx == 1 { // 取消
  333. self?.cropCancelAction()
  334. }
  335. }
  336. }
  337. func hiddenCropComfirmWindow() {
  338. let winC = KMEditPDFCropComfirmWindowController.shared
  339. winC.window?.orderOut(nil)
  340. winC.window?.setIsVisible(false)
  341. self._kRemoveChildWindow(winC.window)
  342. }
  343. func showGuideView(_ view: NSView) {
  344. DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  345. if KMGuideInfoWindowController.availableShow(.editPDFPopWindow) {
  346. var winFrame = self.viewC?.view.window?.frame ?? .zero
  347. winFrame.size.height -= 20
  348. guard let area = (self.listView?.editingAreas().first as? CPDFEditArea) else {
  349. return
  350. }
  351. var areaBounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  352. var maxX = NSMaxX(areaBounds)
  353. var maxY = NSMaxY(areaBounds)
  354. for area in self.editingAreas {
  355. // let bounds = area.bounds
  356. let bounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  357. areaBounds.origin.x = min(areaBounds.origin.x, bounds.origin.x)
  358. areaBounds.origin.y = min(areaBounds.origin.y, bounds.origin.y)
  359. maxX = max(maxX, NSMaxX(bounds))
  360. areaBounds.size.width = maxX-areaBounds.origin.x
  361. maxY = max(maxY, NSMaxY(bounds))
  362. areaBounds.size.height = maxY-areaBounds.origin.y
  363. }
  364. let guideWC = KMGuideInfoWindowController.currentWC()
  365. guideWC.type = .editPDFPopWindow
  366. var viewFrame = areaBounds
  367. let tmpY = areaBounds.origin.y+(areaBounds.size.height-KMEditPDFPopGuideView.kHeight+80)
  368. if tmpY < 50 {
  369. guideWC.editPDFPopWindowFlag = true
  370. viewFrame.origin.y += (areaBounds.size.height)
  371. viewFrame.origin.x += (areaBounds.size.width*0.5+KMEditPDFPopGuideView.kWidth*0.5)
  372. viewFrame.origin.y += 20
  373. } else {
  374. guideWC.editPDFPopWindowFlag = false
  375. viewFrame.origin.y += (areaBounds.size.height-KMEditPDFPopGuideView.kHeight+80)
  376. viewFrame.origin.x += (areaBounds.size.width*0.5+KMEditPDFPopGuideView.kWidth*0.5)
  377. viewFrame.size.height = KMEditPDFPopGuideView.kHeight+80
  378. let offsetY = NSMaxY(winFrame)-NSMaxY(viewFrame)-NSMinY(winFrame)
  379. if offsetY <= 0 {
  380. viewFrame.origin.y += offsetY
  381. }
  382. }
  383. guideWC.digitalBoxRect = viewFrame
  384. var beh = view.window?.collectionBehavior ?? []
  385. beh.insert(.canJoinAllSpaces)
  386. guideWC.window?.collectionBehavior = beh
  387. guideWC.window?.setFrame(winFrame, display: false)
  388. guideWC.window?.minSize = winFrame.size
  389. guideWC.window?.maxSize = winFrame.size
  390. self._kAddchildwindow(guideWC.window!)
  391. guideWC.show()
  392. DispatchQueue.main.async {
  393. guideWC.interfaceThemeDidChanged(NSApp.appearance?.name ?? .aqua)
  394. }
  395. guideWC.settingCallback = {
  396. KMPreferenceController.shared.showWindow(nil)
  397. }
  398. }
  399. }
  400. }
  401. func clearData() {
  402. self.hiddenWindows()
  403. self._removeNotification()
  404. }
  405. func hiddenWindows() {
  406. self.hiddenPopWindow()
  407. self.hiddenCropComfirmWindow()
  408. KMColorPanelCloseIfNeed()
  409. }
  410. }
  411. // MARK: - Private Methods
  412. extension KMEditPDfHanddler {
  413. private func _kAddchildwindow(_ childW: NSWindow?) {
  414. guard let win = childW else {
  415. return
  416. }
  417. self.viewC?.view.window?.addChildWindow(win, ordered: .above)
  418. }
  419. private func _kRemoveChildWindow(_ childW: NSWindow?) {
  420. guard let win = childW else {
  421. return
  422. }
  423. let contains = self.viewC?.view.window?.childWindows?.contains(win) ?? false
  424. if contains {
  425. self.viewC?.view.window?.removeChildWindow(win)
  426. }
  427. }
  428. private func _addNotification() {
  429. NotificationCenter.default.addObserver(self, selector: #selector(_scrollViewDidScroll), name: NSScrollView.didLiveScrollNotification, object: self.listView?.documentView())
  430. }
  431. private func _removeNotification() {
  432. NotificationCenter.default.removeObserver(self, name: NSScrollView.didLiveScrollNotification, object: self.listView?.documentView())
  433. }
  434. @objc private func _scrollViewDidScroll(_ noti: Notification) {
  435. if let data = self.listView?.documentView().isEqual(to: noti.object), data {
  436. let win = KMEditPDFPopToolBarWindow.shared
  437. if win.isVisible == false {
  438. // return
  439. }
  440. guard let area = (self.listView?.editingAreas()?.first as? CPDFEditArea) else {
  441. self.hiddenPopWindow()
  442. self.hiddenCropComfirmWindow()
  443. return
  444. }
  445. let isEditImage = self.listView?.isEditImage ?? false
  446. if isEditImage {
  447. let winC = KMEditPDFCropComfirmWindowController.shared
  448. let winW: CGFloat = 84
  449. let areaBounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  450. let winFrame = self.listView?.window?.frame ?? .zero
  451. let view: NSView? = nil
  452. var position = self.listView?.convert(areaBounds.origin, to: view) ?? .zero
  453. position.x += winFrame.origin.x
  454. position.y += winFrame.origin.y
  455. position.y += areaBounds.size.height
  456. position.y += 26
  457. var x = position.x + (NSWidth(areaBounds)-84) * 0.5
  458. // let frame = NSMakeRect(x, position.y, 84, 44)
  459. // position.x += (areaBounds.size.width*0.5-win.frame.size.width*0.5)
  460. x = max(0, x)
  461. var y = max(0, position.y)
  462. let screenFrame = NSScreen.main?.frame ?? .zero
  463. if y + 44 + 40 >= screenFrame.size.height {
  464. y = screenFrame.size.height - 44 - 40
  465. }
  466. let wframe = NSMakeRect(x, y, winW, 44)
  467. winC.window?.setFrame(wframe, display: true)
  468. if winFrame.contains(wframe) == false {
  469. self.hiddenCropComfirmWindow()
  470. } else {
  471. self.showCropComfirmWindow()
  472. }
  473. return
  474. }
  475. var areaBounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  476. var maxX = NSMaxX(areaBounds)
  477. var maxY = NSMaxY(areaBounds)
  478. for area in self.editingAreas {
  479. // let bounds = area.bounds
  480. let bounds = (self.listView?.convert(area.bounds, from: area.page) as? NSRect) ?? .zero
  481. areaBounds.origin.x = min(areaBounds.origin.x, bounds.origin.x)
  482. areaBounds.origin.y = min(areaBounds.origin.y, bounds.origin.y)
  483. maxX = max(maxX, NSMaxX(bounds))
  484. areaBounds.size.width = maxX-areaBounds.origin.x
  485. maxY = max(maxY, NSMaxY(bounds))
  486. areaBounds.size.height = maxY-areaBounds.origin.y
  487. }
  488. let winFrame = self.listView?.window?.frame ?? .zero
  489. let view: NSView? = nil
  490. var position = self.listView?.convert(areaBounds.origin, to: view) ?? .zero
  491. if position.y > winFrame.height {
  492. self.hiddenPopWindow()
  493. return
  494. }
  495. position.x += winFrame.origin.x
  496. position.y += winFrame.origin.y
  497. position.y += areaBounds.size.height
  498. position.y += 26
  499. position.x += (areaBounds.size.width*0.5-win.frame.size.width*0.5)
  500. // var x = max(0, position.x)
  501. var x = max(winFrame.origin.x, position.x)
  502. let width = win.frame.size.width
  503. let offsetX = x + width - NSMaxX(winFrame)
  504. if offsetX > 0 { // 超出右编辑
  505. x -= offsetX
  506. }
  507. var y = max(0, position.y)
  508. // let screenFrame = NSScreen.main?.frame ?? .zero
  509. // let winMaxY = NSMaxY(winFrame)
  510. let height = NSHeight(winFrame)
  511. if y + 44 + 40-20 >= height {
  512. // if y + 44 + 40 + 40 >= screenFrame.size.height {
  513. // y = screenFrame.size.height - 44 - 40 - 40
  514. y = height - 44 - 40 + 20
  515. }
  516. let wframe = NSMakeRect(x, y, width, 44)
  517. win.setFrame(wframe, display: true)
  518. if winFrame.contains(wframe) == false {
  519. self.hiddenPopWindow()
  520. }
  521. }
  522. }
  523. private func _reloadData_right_text() {
  524. self.rightViewC?.eidtPDFTextProperty.handdler = self
  525. self.rightViewC?.eidtPDFTextProperty.reloadData()
  526. }
  527. private func _reloadData_right_image() {
  528. self.rightViewC?.eidtPDFImageProperty.handdler = self
  529. self.rightViewC?.eidtPDFImageProperty.reloadData()
  530. }
  531. }
  532. // MARK: - Tools
  533. extension KMEditPDfHanddler {
  534. func editAreasIsEmpty() -> Bool {
  535. return self.editingAreas.isEmpty
  536. }
  537. func editAreasHavTextArea() -> Bool {
  538. return self.editingTextAreas.isEmpty == false
  539. }
  540. func editAreasHavImageArea() -> Bool {
  541. return self.editingImageAreas.isEmpty == false
  542. }
  543. func editAreasFontColorIsEqual() -> Bool {
  544. if self.editAreasIsEmpty() {
  545. return false
  546. }
  547. let datas = self._editAreasFontColors()
  548. if datas.count == 1 {
  549. return true
  550. }
  551. let color = datas.first
  552. for (i, d) in datas.enumerated() {
  553. if i == 0 {
  554. continue
  555. }
  556. if d != color {
  557. return false
  558. }
  559. }
  560. return true
  561. }
  562. func editAreasFontNameIsEqual() -> Bool {
  563. if self.editAreasIsEmpty() {
  564. return false
  565. }
  566. let datas = self._editAreasFontNames()
  567. if datas.count == 1 {
  568. return true
  569. }
  570. let data = datas.first
  571. for (i, d) in datas.enumerated() {
  572. if i == 0 {
  573. continue
  574. }
  575. if d != data {
  576. return false
  577. }
  578. }
  579. return true
  580. }
  581. func editAreasFontStyleIsEqual() -> Bool {
  582. if self.editAreasIsEmpty() {
  583. return false
  584. }
  585. let datas = self._editAreasFontStyles()
  586. if datas.count == 1 {
  587. return true
  588. }
  589. let data = datas.first
  590. for (i, d) in datas.enumerated() {
  591. if i == 0 {
  592. continue
  593. }
  594. if d != data {
  595. return false
  596. }
  597. }
  598. return true
  599. }
  600. func editAreasFontSizeIsEqual() -> Bool {
  601. if self.editAreasIsEmpty() {
  602. return false
  603. }
  604. let datas = self._editAreasFontSizes()
  605. if datas.count == 1 {
  606. return true
  607. }
  608. let data = datas.first
  609. for (i, d) in datas.enumerated() {
  610. if i == 0 {
  611. continue
  612. }
  613. if d != data {
  614. return false
  615. }
  616. }
  617. return true
  618. }
  619. func editAreasFontBoldIsEqual() -> Bool {
  620. if self.editAreasIsEmpty() {
  621. return false
  622. }
  623. let datas = self._editAreasFontBolds()
  624. if datas.count == 1 {
  625. return true
  626. }
  627. let data = datas.first
  628. for (i, d) in datas.enumerated() {
  629. if i == 0 {
  630. continue
  631. }
  632. if d != data {
  633. return false
  634. }
  635. }
  636. return true
  637. }
  638. func editAreasFontItalicIsEqual() -> Bool {
  639. if self.editAreasIsEmpty() {
  640. return false
  641. }
  642. let datas = self._editAreasFontItalics()
  643. if datas.count == 1 {
  644. return true
  645. }
  646. let data = datas.first
  647. for (i, d) in datas.enumerated() {
  648. if i == 0 {
  649. continue
  650. }
  651. if d != data {
  652. return false
  653. }
  654. }
  655. return true
  656. }
  657. func editAreasTextAlignmentIsEqual() -> Bool {
  658. if self.editAreasIsEmpty() {
  659. return false
  660. }
  661. let datas = self._editAreasTextAlignments()
  662. if datas.count == 1 {
  663. return true
  664. }
  665. let data = datas.first?.rawValue ?? 0
  666. for (i, d) in datas.enumerated() {
  667. if i == 0 {
  668. continue
  669. }
  670. if d.rawValue != data {
  671. return false
  672. }
  673. }
  674. return true
  675. }
  676. func editAreasBoundsIsEqualForWidth() -> Bool {
  677. if self.editAreasIsEmpty() {
  678. return false
  679. }
  680. let rects = self._editAreasBounds()
  681. if rects.count == 1 {
  682. return true
  683. }
  684. let width = rects.first?.width ?? 0
  685. for (i, rect) in rects.enumerated() {
  686. if i == 0 {
  687. continue
  688. }
  689. if abs(width-rect.size.width) > 0.01 {
  690. // if width != rect.size.width {
  691. return false
  692. }
  693. }
  694. return true
  695. }
  696. func editAreasBoundsIsEqualForHeight() -> Bool {
  697. if self.editAreasIsEmpty() {
  698. return false
  699. }
  700. let rects = self._editAreasBounds()
  701. if rects.count == 1 {
  702. return true
  703. }
  704. let height = rects.first?.height ?? 0
  705. for (i, rect) in rects.enumerated() {
  706. if i == 0 {
  707. continue
  708. }
  709. // if height != rect.size.height {
  710. if abs(height-rect.size.height) > 0.01 {
  711. return false
  712. }
  713. }
  714. return true
  715. }
  716. func editAreasRotateIsEqual() -> Bool {
  717. if self.editAreasIsEmpty() {
  718. return false
  719. }
  720. if self.editAreasHavTextArea() {
  721. return false
  722. }
  723. let datas = self._editAreasRotates()
  724. if datas.count == 1 {
  725. return true
  726. }
  727. let data = datas.first ?? 0
  728. for (i, d) in datas.enumerated() {
  729. if i == 0 {
  730. continue
  731. }
  732. if data != d {
  733. return false
  734. }
  735. }
  736. return true
  737. }
  738. func editAreasOpacityIsEqual() -> Bool {
  739. if self.editAreasIsEmpty() {
  740. return false
  741. }
  742. let datas = self._editAreasOpacitys()
  743. if datas.count == 1 {
  744. return true
  745. }
  746. let data = datas.first ?? 0
  747. for (i, d) in datas.enumerated() {
  748. if i == 0 {
  749. continue
  750. }
  751. if data != d {
  752. return false
  753. }
  754. }
  755. return true
  756. }
  757. private func _editAreasFontColors() -> [NSColor] {
  758. var datas: [NSColor] = []
  759. for area in self.editingTextAreas {
  760. if let data = self.listView?.editingSelectionFontColor(with: area) {
  761. // if let data = self.listView?.editingSelectionFontColor(byRangeEdit: area) {
  762. datas.append(data)
  763. }
  764. }
  765. return datas
  766. }
  767. private func _editAreasFontStyles() -> [String] {
  768. var datas: [String] = []
  769. for area in self.editingTextAreas {
  770. if let data = self.listView?.editingSelectionCFont(byRangeEdit: area)?.styleName {
  771. // if let data = self.listView?.editingSelectionCFont(with: area)?.familyName {
  772. datas.append(data)
  773. }
  774. }
  775. return datas
  776. }
  777. private func _editAreasFontNames() -> [String] {
  778. var datas: [String] = []
  779. for area in self.editingTextAreas {
  780. if let data = self.listView?.editingSelectionCFont(byRangeEdit: area)?.familyName {
  781. // if let data = self.listView?.editingSelectionCFont(with: area)?.familyName {
  782. datas.append(data)
  783. }
  784. }
  785. return datas
  786. }
  787. private func _editAreasFontSizes() -> [CGFloat] {
  788. var datas: [CGFloat] = []
  789. for area in self.editingTextAreas {
  790. if let data = self.listView?.editingSelectionFontSize(byRangeEdit: area) {
  791. datas.append(data)
  792. }
  793. }
  794. return datas
  795. }
  796. private func _editAreasFontBolds() -> [Bool] {
  797. var datas: [Bool] = []
  798. for area in self.editingTextAreas {
  799. if let data = self.listView?.isBoldCurrentSelection(byRangeEdit: area) {
  800. datas.append(data)
  801. }
  802. }
  803. return datas
  804. }
  805. private func _editAreasFontItalics() -> [Bool] {
  806. var datas: [Bool] = []
  807. for area in self.editingTextAreas {
  808. if let data = self.listView?.isItalicCurrentSelection(byRangeEdit: area) {
  809. datas.append(data)
  810. }
  811. }
  812. return datas
  813. }
  814. private func _editAreasTextAlignments() -> [NSTextAlignment] {
  815. var datas: [NSTextAlignment] = []
  816. for area in self.editingTextAreas {
  817. if let data = self.listView?.currentSelectionAlignment(byRangeEdit: area) {
  818. datas.append(data)
  819. }
  820. }
  821. return datas
  822. }
  823. private func _editAreasBounds() -> [NSRect] {
  824. var rects: [NSRect] = []
  825. for area in self.editingAreas {
  826. rects.append(area.bounds)
  827. }
  828. return rects
  829. }
  830. private func _editAreasRotates() -> [CGFloat] {
  831. var arr: [CGFloat] = []
  832. for area in self.editingImageAreas {
  833. if let data = self.listView?.getRotateWith(area) {
  834. arr.append(data)
  835. }
  836. }
  837. return arr
  838. }
  839. private func _editAreasOpacitys() -> [CGFloat] {
  840. var arr: [CGFloat] = []
  841. for area in self.editingAreas {
  842. if let data = self.listView?.opacityByRange(for: area) {
  843. arr.append(data)
  844. }
  845. }
  846. return arr
  847. }
  848. }
  849. // MARK: - Action
  850. extension KMEditPDfHanddler {
  851. func fontColorAction(color: NSColor?) {
  852. guard let theColor = color else {
  853. return
  854. }
  855. let areas = self.editingTextAreas
  856. for area in areas {
  857. self.listView?.setEditingSelectionFontColor(theColor, with: area)
  858. }
  859. self._reloadData_right_text()
  860. }
  861. func fontStyleAction(fontName: String?) {
  862. guard let font = CPDFFont.mappingFont(withFontString: fontName) else {
  863. return
  864. }
  865. let areas = self.editingTextAreas
  866. for area in areas {
  867. self.listView?.setEditSelectionCFont(font, with: area)
  868. }
  869. self._reloadData_right_text()
  870. }
  871. func fontAddAction() {
  872. let areas = self.editingTextAreas
  873. for area in areas {
  874. if let fontSize = self.listView?.editingSelectionFontSize(byRangeEdit: area) {
  875. self.fontSizeChanging = true
  876. self.listView?.setEditingSelectionFontSize(fontSize+1, with: area, isAutoSize: false)
  877. self.fontSizeChanging = false
  878. }
  879. }
  880. self._reloadData_right_text()
  881. }
  882. func fontReduceAction() {
  883. let areas = self.editingTextAreas
  884. for area in areas {
  885. if let fontSize = self.listView?.editingSelectionFontSize(byRangeEdit: area) {
  886. self.fontSizeChanging = true
  887. self.listView?.setEditingSelectionFontSize(fontSize-1, with: area, isAutoSize: false)
  888. self.fontSizeChanging = false
  889. }
  890. }
  891. self._reloadData_right_text()
  892. }
  893. func fontBoldAction() {
  894. let areas = self.editingTextAreas
  895. var needTip = false
  896. for area in areas {
  897. if let data = self.listView?.isBoldCurrentSelection(byRangeEdit: area) {
  898. let result = self.listView?.setCurrentSelectionIsBold(!data, with: area)
  899. if (result == nil || result == false) && needTip == false {
  900. needTip = true
  901. }
  902. }
  903. }
  904. if needTip {
  905. if let data = self.viewC?.view {
  906. _ = CustomAlertView.alertView(message: NSLocalizedString("Please reset the font weight via the drop-down box", comment: ""), fromView: data, withStyle: .black)
  907. }
  908. }
  909. self._reloadData_right_text()
  910. }
  911. func fontItalicAction() {
  912. let areas = self.editingTextAreas
  913. var needTip = false
  914. for area in areas {
  915. if let data = self.listView?.isItalicCurrentSelection(byRangeEdit: area) {
  916. let result = self.listView?.setCurrentSelectionIsItalic(!data, with: area)
  917. if (result == nil || result == false) && needTip == false {
  918. needTip = true
  919. }
  920. }
  921. }
  922. if needTip {
  923. if let data = self.viewC?.view {
  924. _ = CustomAlertView.alertView(message: NSLocalizedString("Please reset the font weight via the drop-down box", comment: ""), fromView: data, withStyle: .black)
  925. }
  926. }
  927. self._reloadData_right_text()
  928. }
  929. func textAlignmentAction(align: NSTextAlignment) {
  930. let areas = self.editingTextAreas
  931. self.textAlignChanging = true
  932. for area in areas {
  933. self.listView?.setCurrentSelectionAlignment(align, with: area)
  934. }
  935. self.textAlignChanging = false
  936. self._reloadData_right_text()
  937. }
  938. func leftRotateAction() {
  939. let areas = self.editingImageAreas
  940. for area in areas {
  941. self.listView?.rotate(with: area, rotate: -90)
  942. }
  943. }
  944. func rightRotateAction() {
  945. let areas = self.editingImageAreas
  946. for area in areas {
  947. self.listView?.rotate(with: area, rotate: 90)
  948. }
  949. }
  950. func reverseXAction() {
  951. let areas = self.editingImageAreas
  952. for area in areas {
  953. self.listView?.horizontalMirror(with: area)
  954. }
  955. }
  956. func reverseYAction() {
  957. let areas = self.editingImageAreas
  958. for area in areas {
  959. self.listView?.verticalMirror(with: area)
  960. }
  961. }
  962. func cropAction() {
  963. let areas = self.editingImageAreas
  964. if areas.isEmpty {
  965. return
  966. }
  967. self.listView?.isEditImage = true
  968. for area in areas {
  969. self.listView?.enterCrop(with: area)
  970. }
  971. self.hiddenPopWindow()
  972. Task { @MainActor in
  973. self.showCropComfirmWindow()
  974. }
  975. self.rightViewC?.eidtPDFImageProperty.handdler = self
  976. self.rightViewC?.eidtPDFImageProperty.updateButtonState(hidden: false)
  977. self.viewC?.view.window?.makeFirstResponder(self.listView)
  978. }
  979. func cropCancelAction() {
  980. self.hiddenCropComfirmWindow()
  981. let areas = self.editingImageAreas
  982. if areas.isEmpty {
  983. return
  984. }
  985. for area in areas {
  986. self.listView?.exitCrop(with: area)
  987. }
  988. self.listView?.cropAreas = nil
  989. self.listView?.isEditImage = false
  990. self.rightViewC?.eidtPDFImageProperty.handdler = self
  991. self.rightViewC?.eidtPDFImageProperty.updateButtonState(hidden: true)
  992. Task { @MainActor [weak self] in
  993. if let data = self?.listView?.selectImageAreas {
  994. self?.showPopWindow(positionRect:data.bounds, showGuide: false)
  995. }
  996. }
  997. }
  998. func cropComfirmAction() {
  999. guard let selectImageAreas = self.listView?.selectImageAreas else {
  1000. self.cropCancelAction()
  1001. return
  1002. }
  1003. self.listView?.cropEditImageArea(selectImageAreas, withBounds: self.listView?.cropAreas.cropRect ?? .zero)
  1004. self.cropCancelAction()
  1005. }
  1006. func replaceAction() {
  1007. let areas = self.editingImageAreas
  1008. if areas.isEmpty {
  1009. return
  1010. }
  1011. let panel = NSOpenPanel()
  1012. panel.allowsMultipleSelection = false
  1013. panel.allowedFileTypes = ["png","jpg"]
  1014. panel.beginSheetModal(for: NSApp.mainWindow!) { response in
  1015. if response == .OK {
  1016. let openPath = panel.url?.path
  1017. for area in areas {
  1018. // , rect: data.bounds
  1019. self.listView?.replace(area, imagePath: openPath!)
  1020. }
  1021. }
  1022. }
  1023. }
  1024. func showExportMenu(_ sender: NSView) {
  1025. // let menuI = NSMenuItem()
  1026. let submenu = NSMenu(title: "")
  1027. let jpgMI = submenu.addItem(withTitle: "jpg", action: #selector(exportMenuItemAction), keyEquivalent: "")
  1028. jpgMI.target = self
  1029. jpgMI.tag = 1
  1030. let pngMI = submenu.addItem(withTitle: "png", action: #selector(exportMenuItemAction), keyEquivalent: "")
  1031. pngMI.target = self
  1032. pngMI.tag = 2
  1033. let pdfMI = submenu.addItem(withTitle: "pdf", action: #selector(exportMenuItemAction), keyEquivalent: "")
  1034. pdfMI.target = self
  1035. pdfMI.tag = 3
  1036. let p = NSPoint(x: NSMidX(sender.frame), y: NSMidY(sender.frame))
  1037. submenu.popUp(positioning: nil, at: p, in: sender.superview)
  1038. }
  1039. @objc func exportMenuItemAction(_ sender: NSMenuItem) {
  1040. var format = ""
  1041. if sender.tag == 1 {
  1042. format = "jpg"
  1043. } else if sender.tag == 2 {
  1044. format = "png"
  1045. } else if sender.tag == 3 {
  1046. format = "pdf"
  1047. }
  1048. self.exportAction(format: format)
  1049. }
  1050. func exportAction(format: String) {
  1051. let areas = self.editingImageAreas
  1052. if areas.isEmpty {
  1053. return
  1054. }
  1055. if areas.count == 1 {
  1056. if KMTools.isPDFType(format) {
  1057. guard let image = areas.first?.thumbnailImage else {
  1058. NSSound.beep()
  1059. return
  1060. }
  1061. let pdfdocument = CPDFDocument()
  1062. pdfdocument?.km_insert(image: image, at: 0)
  1063. let savePanel = NSSavePanel()
  1064. savePanel.allowedFileTypes = ["pdf"]
  1065. savePanel.beginSheetModal(for: self.viewC!.view.window!) { response in
  1066. if (response != .OK) {
  1067. return
  1068. }
  1069. if let data = pdfdocument?.write(to: savePanel.url!), data {
  1070. NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: "");
  1071. }
  1072. }
  1073. return
  1074. }
  1075. let panel = NSSavePanel()
  1076. panel.nameFieldStringValue = "\(NSLocalizedString("Untitled", comment: "")).\(format)"
  1077. panel.isExtensionHidden = true
  1078. let response = panel.runModal()
  1079. if response == .OK {
  1080. let url = panel.url
  1081. if FileManager.default.fileExists(atPath: url!.path) {
  1082. try?FileManager.default.removeItem(atPath: url!.path)
  1083. }
  1084. let result = self.listView?.extractImage(with: areas.first, toImagePath: url!.path) ?? false
  1085. if result {
  1086. NSWorkspace.shared.activateFileViewerSelecting([url!])
  1087. }
  1088. }
  1089. } else if areas.count > 1 {
  1090. let panel = NSOpenPanel()
  1091. panel.canChooseFiles = false
  1092. panel.canChooseDirectories = true
  1093. panel.canCreateDirectories = true
  1094. panel.allowsMultipleSelection = false
  1095. panel.beginSheetModal(for: NSApp.mainWindow!) { response in
  1096. if response == .OK {
  1097. let outputURL = panel.url
  1098. let s = self.listView?.document?.documentURL.lastPathComponent
  1099. let folderPath = (self.listView?.document?.documentURL.deletingPathExtension().lastPathComponent ?? "") + "_extract"
  1100. var filePath = outputURL?.path.stringByAppendingPathComponent(folderPath)
  1101. var i = 1
  1102. let testFilePath = filePath
  1103. while FileManager.default.fileExists(atPath: filePath!) {
  1104. filePath = testFilePath! + "\(i)"
  1105. i = i + 1
  1106. }
  1107. try? FileManager.default.createDirectory(atPath: filePath!, withIntermediateDirectories: false, attributes: nil)
  1108. var saveURLs : [URL] = []
  1109. let pageIndex = self.listView?.currentPageIndex ?? 0
  1110. for j in 0 ..< areas.count {
  1111. let documentFileName = self.listView?.document?.documentURL.deletingPathExtension().lastPathComponent ?? ""
  1112. var outPath = filePath!
  1113. outPath = outPath.stringByAppendingPathComponent(documentFileName)
  1114. outPath = outPath + "_page\(pageIndex+1)_\(j+1)"
  1115. outPath = outPath.stringByAppendingPathExtension(format)
  1116. if KMTools.isPDFType(format) {
  1117. if let image = areas[j].thumbnailImage {
  1118. let pdfdocument = CPDFDocument()
  1119. pdfdocument?.km_insert(image: image, at: 0)
  1120. let suc = pdfdocument?.write(toFile: outPath) ?? false
  1121. if suc {
  1122. saveURLs.append(URL(fileURLWithPath: outPath))
  1123. }
  1124. }
  1125. } else {
  1126. let result = self.listView?.extractImage(with: areas[j], toImagePath: outPath) ?? false
  1127. if result {
  1128. saveURLs.append(URL(fileURLWithPath: outPath))
  1129. }
  1130. }
  1131. }
  1132. NSWorkspace.shared.activateFileViewerSelecting(saveURLs)
  1133. }
  1134. }
  1135. }
  1136. }
  1137. func alignmentAction(align: CPDFActiveAreasAlignType) {
  1138. KMPrint("updateFormAearsAlignMangent")
  1139. let stype = align
  1140. let editingAreas = self.editingAreas
  1141. if editingAreas.count >= 2 {
  1142. var zeroRect = NSRect.null
  1143. var highestRect = NSZeroRect
  1144. var widthestRect = NSZeroRect
  1145. let fristArea : CPDFEditArea = editingAreas.first as! CPDFEditArea
  1146. var leftestRect = fristArea.bounds
  1147. var rightestRect = fristArea.bounds
  1148. var topestRect = fristArea.bounds
  1149. var bottomestRect = fristArea.bounds
  1150. var leftestArea : CPDFEditArea = fristArea
  1151. var rightestArea : CPDFEditArea = fristArea
  1152. var topestArea : CPDFEditArea = fristArea
  1153. var bottomestArea : CPDFEditArea = fristArea
  1154. var totalWidth = 0.0
  1155. var totalHeight = 0.0
  1156. for i in 0 ... editingAreas.count-1 {
  1157. let area : CPDFEditArea = editingAreas[i] as! CPDFEditArea
  1158. zeroRect = zeroRect.union(area.bounds)
  1159. totalWidth = totalWidth + area.bounds.width
  1160. totalHeight = totalHeight + area.bounds.height
  1161. if area.bounds.height > highestRect.height {
  1162. highestRect = area.bounds
  1163. }
  1164. if area.bounds.width > widthestRect.width {
  1165. widthestRect = area.bounds
  1166. }
  1167. if leftestRect.minX > area.bounds.minX {
  1168. leftestRect = area.bounds
  1169. leftestArea = area
  1170. }
  1171. if area.bounds.maxX > rightestRect.maxX {
  1172. rightestRect = area.bounds
  1173. rightestArea = area
  1174. }
  1175. if area.bounds.maxY > topestRect.maxY {
  1176. topestRect = area.bounds
  1177. topestArea = area
  1178. }
  1179. if bottomestRect.minY > area.bounds.minY {
  1180. bottomestRect = area.bounds
  1181. bottomestArea = area
  1182. }
  1183. }
  1184. var resultAreasArray: [Any] = []
  1185. var newBoundsArray: [String] = []
  1186. if stype == .Left {
  1187. for i in 0 ... editingAreas.count-1 {
  1188. let areas = editingAreas[i] as! CPDFEditArea
  1189. var bounds = areas.bounds
  1190. bounds.origin.x = zeroRect.origin.x
  1191. newBoundsArray.append(NSStringFromRect(bounds))
  1192. }
  1193. resultAreasArray = editingAreas
  1194. } else if stype == .Right {
  1195. for i in 0 ... editingAreas.count-1 {
  1196. let areas = editingAreas[i] as! CPDFEditArea
  1197. var bounds = areas.bounds
  1198. bounds.origin.x = zeroRect.maxX - bounds.size.width
  1199. newBoundsArray.append(NSStringFromRect(bounds))
  1200. }
  1201. resultAreasArray = editingAreas
  1202. } else if stype == .Top {
  1203. for i in 0 ... editingAreas.count-1 {
  1204. let areas = editingAreas[i] as! CPDFEditArea
  1205. var bounds = areas.bounds
  1206. bounds.origin.y = zeroRect.maxY - bounds.size.height
  1207. newBoundsArray.append(NSStringFromRect(bounds))
  1208. }
  1209. resultAreasArray = editingAreas
  1210. } else if stype == .Bottom {
  1211. for i in 0 ... editingAreas.count-1 {
  1212. let areas = editingAreas[i] as! CPDFEditArea
  1213. var bounds = areas.bounds
  1214. bounds.origin.y = zeroRect.minY
  1215. newBoundsArray.append(NSStringFromRect(bounds))
  1216. }
  1217. resultAreasArray = editingAreas
  1218. } else if stype == .Horizontally {
  1219. for i in 0 ... editingAreas.count-1 {
  1220. let areas = editingAreas[i] as! CPDFEditArea
  1221. var bounds = areas.bounds
  1222. bounds.origin.y = highestRect.midY - bounds.height/2
  1223. newBoundsArray.append(NSStringFromRect(bounds))
  1224. }
  1225. resultAreasArray = editingAreas
  1226. } else if stype == .Vertical {
  1227. for i in 0 ... editingAreas.count-1 {
  1228. let areas = editingAreas[i] as! CPDFEditArea
  1229. var bounds = areas.bounds
  1230. bounds.origin.x = widthestRect.midX - bounds.width/2
  1231. newBoundsArray.append(NSStringFromRect(bounds))
  1232. }
  1233. resultAreasArray = editingAreas
  1234. } else if stype == .DisHorizontally {
  1235. let middleGap = zeroRect.width - leftestRect.width - rightestRect.width
  1236. let otherAreasTotalWidth = totalWidth - leftestRect.width - rightestRect.width
  1237. let gap = (middleGap - otherAreasTotalWidth)/CGFloat(editingAreas.count - 1)
  1238. var areasCopyArray : [CPDFEditArea] = editingAreas as! [CPDFEditArea]
  1239. areasCopyArray.sorted(by: { obj1, obj2 in
  1240. let area1 = obj1
  1241. let area2 = obj2
  1242. if area1.bounds.origin.x < area2.bounds.origin.x {
  1243. return true
  1244. } else {
  1245. return false
  1246. }
  1247. })
  1248. if let index = areasCopyArray.firstIndex(of: leftestArea) {
  1249. areasCopyArray.remove(at: index)
  1250. }
  1251. if let index = areasCopyArray.firstIndex(of: rightestArea) {
  1252. areasCopyArray.remove(at: index)
  1253. }
  1254. var leftStartX = leftestRect.maxX + gap
  1255. for i in 0 ..< areasCopyArray.count {
  1256. let areas = areasCopyArray[i]
  1257. var bounds = areas.bounds
  1258. bounds.origin.x = leftStartX
  1259. newBoundsArray.append(NSStringFromRect(bounds))
  1260. leftStartX = leftStartX + bounds.width + gap
  1261. }
  1262. resultAreasArray = areasCopyArray
  1263. } else if stype == .DisVertical {
  1264. let middleGap = zeroRect.height - topestRect.height - bottomestRect.height
  1265. let otherAreasTotalHeight = totalHeight - topestRect.height - bottomestRect.height
  1266. let gap = (middleGap - otherAreasTotalHeight)/CGFloat(editingAreas.count - 1)
  1267. var areasCopyArray : [CPDFEditArea] = editingAreas as! [CPDFEditArea]
  1268. areasCopyArray.sorted(by: { obj1, obj2 in
  1269. let area1 = obj1
  1270. let area2 = obj2
  1271. if area1.bounds.origin.x < area2.bounds.origin.x {
  1272. return true
  1273. } else {
  1274. return false
  1275. }
  1276. })
  1277. if let index = areasCopyArray.firstIndex(of: topestArea) {
  1278. areasCopyArray.remove(at: index)
  1279. }
  1280. if let index = areasCopyArray.firstIndex(of: bottomestArea) {
  1281. areasCopyArray.remove(at: index)
  1282. }
  1283. var bottomStartY = bottomestRect.maxY + gap
  1284. for i in 0 ... areasCopyArray.count-1 {
  1285. let areas = areasCopyArray[i]
  1286. var bounds = areas.bounds
  1287. bounds.origin.y = bottomStartY
  1288. newBoundsArray.append(NSStringFromRect(bounds))
  1289. bottomStartY = bottomStartY + bounds.height + gap
  1290. }
  1291. resultAreasArray = areasCopyArray
  1292. }
  1293. var oldBounds : [String] = []
  1294. for i in 0 ..< resultAreasArray.count {
  1295. let area : CPDFEditArea = resultAreasArray[i] as! CPDFEditArea
  1296. oldBounds.append(NSStringFromRect(area.bounds))
  1297. self.listView?.setBoundsEditArea(area, withBounds: NSRectFromString(newBoundsArray[i]))
  1298. }
  1299. self.listView?.setNeedsDisplayForVisiblePages()
  1300. }
  1301. }
  1302. }
  1303. // MARK: - CPDFViewDelegate
  1304. extension KMEditPDfHanddler: CPDFViewDelegate {
  1305. // 编辑区块已经改变
  1306. func pdfViewEditingAreaDidChanged(_ pdfView: CPDFView!) {
  1307. let isEdited = self.listView?.isEdited() ?? false
  1308. if isEdited {
  1309. // 记录编辑状态
  1310. self.viewC?.recordIsPDFDocumentEdited(type: .editText)
  1311. }
  1312. if annotationType != .addText {
  1313. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kPDFViewEditingAreaDidChanged"), object: self.listView?.document)
  1314. }
  1315. let areas = self.listView?.editingAreas() as? [CPDFEditArea] ?? []
  1316. if areas.isEmpty {
  1317. self.hiddenPopWindow()
  1318. self.hiddenCropComfirmWindow()
  1319. let toolMode = self.listView?.toolMode ?? .none
  1320. let annotationType = self.annotationType
  1321. if toolMode == .editPDFToolMode {
  1322. if annotationType == .addImage || annotationType == .addText {
  1323. if self.isEditImage {
  1324. self.viewC?.menuItemEditingClick_CropImage(sender: NSMenuItem())
  1325. } else {
  1326. // if self.listView.annotationType == .addImage {
  1327. // self.closeRightPane()
  1328. // }
  1329. if annotationType == .addImage {
  1330. if self.rightViewC?.eidtPDFImageProperty != nil {
  1331. self.rightViewC?.eidtPDFImageProperty.handdler = self
  1332. self.rightViewC?.eidtPDFImageProperty.reloadData()
  1333. }
  1334. }
  1335. // self.openRightPane()
  1336. }
  1337. } else {
  1338. // self.viewC?.closeRightPane()
  1339. self.rightViewC?.isHidden = true
  1340. }
  1341. self.listView?.isEditImage = false
  1342. } else {
  1343. self.rightViewC?.isHidden = true
  1344. self.viewC?.closeRightPane()
  1345. if self.subViewType == .EditPDFAddText && annotationType == .addText {
  1346. self.rightViewC?.eidtPDFTextProperty.handdler = self
  1347. self.rightViewC?.eidtPDFTextProperty.initData()
  1348. }
  1349. }
  1350. return
  1351. }
  1352. self.hiddenCropComfirmWindow()
  1353. self.viewC?.model.isPDFTextImageEdited = true
  1354. let subViewType = self.rightViewC?.subViewType ?? .None
  1355. if self.annotationType == .addImage {
  1356. var isImageArea = false
  1357. for i in 0 ..< areas.count {
  1358. if areas[i] is CPDFEditImageArea {
  1359. isImageArea = true
  1360. }
  1361. }
  1362. if isImageArea {
  1363. self.rightViewC?.isHidden = false
  1364. if self.subViewType == .EditPDFAddImage {
  1365. self.rightViewC?.subViewType = .EditPDFAddImage
  1366. self.rightViewC?.eidtPDFImageProperty.handdler = self
  1367. self.rightViewC?.eidtPDFImageProperty.reloadData()
  1368. }
  1369. self.openRightPane()
  1370. } else {
  1371. self.rightViewC?.isHidden = true
  1372. // self.viewC?.closeRightPane()
  1373. }
  1374. } else if self.subViewType == .EditPDFAddText && annotationType == .addText {
  1375. self.rightViewC?.isHidden = false
  1376. let count = self.listView?.editingSelectionString()?.count ?? 0
  1377. self.rightViewC?.eidtPDFTextProperty.handdler = self
  1378. if count != 0 {
  1379. self.rightViewC?.eidtPDFTextProperty.reloadData()
  1380. } else {
  1381. self.rightViewC?.eidtPDFTextProperty.refreshSelectAreaProperty(needDefaultData: true)
  1382. }
  1383. self.openRightPane()
  1384. } else {
  1385. var textsAreas : [CPDFEditTextArea] = []
  1386. var imagesAreas : [CPDFEditImageArea] = []
  1387. let count = self.listView?.editingAreas()?.count ?? 0
  1388. if count < 1 {
  1389. return
  1390. }
  1391. for i in 0 ..< areas.count {
  1392. if areas[i] is CPDFEditTextArea {
  1393. textsAreas.append(areas[i] as! CPDFEditTextArea)
  1394. }
  1395. if areas[i] is CPDFEditImageArea {
  1396. imagesAreas.append(areas[i] as! CPDFEditImageArea)
  1397. }
  1398. }
  1399. if textsAreas.count > 0 && textsAreas.count == areas.count {
  1400. self.rightViewC?.isHidden = false
  1401. self.rightViewC?.subViewType = .EditPDFAddText
  1402. self.rightViewC?.eidtPDFTextProperty.handdler = self
  1403. self.rightViewC?.eidtPDFTextProperty?.reloadData()
  1404. self.openRightPane()
  1405. } else if imagesAreas.count > 0 {
  1406. self.rightViewC?.isHidden = false
  1407. self.rightViewC?.subViewType = .EditPDFAddImage
  1408. self.rightViewC?.eidtPDFImageProperty.handdler = self
  1409. self.rightViewC?.eidtPDFImageProperty?.reloadData()
  1410. self.openRightPane()
  1411. }
  1412. }
  1413. if self.addTextAreaing == false {
  1414. var flag: CPDFEditArea?
  1415. for area in areas {
  1416. if flag == nil {
  1417. flag = area
  1418. continue
  1419. }
  1420. if let data = flag, data.bounds.maxY < area.bounds.maxY {
  1421. flag = area
  1422. }
  1423. }
  1424. if let data = flag {
  1425. self.showPopWindow(positionRect: data.bounds, showGuide: true)
  1426. }
  1427. }
  1428. }
  1429. func pdfViewEditingCropBoundsDidChanged(_ pdfView: CPDFView!, editing editArea: CPDFEditArea!) {
  1430. if editArea != nil && (editArea is CPDFEditImageArea){
  1431. self.listView?.cropAreas = editArea as? CPDFEditImageArea
  1432. }
  1433. }
  1434. func pdfViewEditingAddImageArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) {
  1435. if self.isEditImage {
  1436. self.viewC?.menuItemEditingClick_CropImage(sender: NSMenuItem())
  1437. } else {
  1438. let window = KMEditPDFPopToolBarWindow.shared
  1439. if (window.isVisible) {
  1440. self.listView?.updateEditing([])
  1441. self.hiddenPopWindow()
  1442. self.hiddenCropComfirmWindow()
  1443. return
  1444. }
  1445. let panel = NSOpenPanel()
  1446. panel.allowsMultipleSelection = false
  1447. panel.allowedFileTypes = ["png","jpg"]
  1448. panel.beginSheetModal(for: NSApp.mainWindow!) { response in
  1449. if response == .OK {
  1450. var filePath = panel.url?.path
  1451. var image = NSImage.init(contentsOf: panel.url!)
  1452. //图片自适应范围
  1453. if image != nil {
  1454. var imageRect = rect
  1455. let imageSize = image!.size
  1456. var previewSize = rect.size
  1457. var isChangeSize = false
  1458. if previewSize.width == 0 && previewSize.height == 0 {
  1459. previewSize = CGSize(width: 500, height: 500)
  1460. isChangeSize = true
  1461. }
  1462. var scale = min(previewSize.width / imageSize.width, previewSize.height / imageSize.height)
  1463. if scale < 1 { // 大于 500
  1464. } else {
  1465. let wh = max(imageSize.width, imageSize.height)
  1466. if wh >= 72 {
  1467. scale = min(scale, 1)
  1468. } else {
  1469. scale = min(72 / imageSize.width, 72 / imageSize.height)
  1470. }
  1471. }
  1472. let newSize = CGSize(width: imageSize.width * scale, height: imageSize.height * scale)
  1473. if isChangeSize {
  1474. imageRect.origin.x = imageRect.origin.x - newSize.width / 2
  1475. imageRect.origin.y = imageRect.origin.y - newSize.height / 2
  1476. } else {
  1477. imageRect.origin.x = imageRect.origin.x + imageRect.width / 2 - newSize.width / 2
  1478. imageRect.origin.y = imageRect.origin.y + imageRect.height / 2 - newSize.height / 2
  1479. }
  1480. imageRect.size = newSize
  1481. let limitWidth = 1920.0
  1482. if imageSize.width > limitWidth || imageSize.height > limitWidth {
  1483. filePath = KMImageOptimization.needCompressImageLosslessly(image: image!,
  1484. targetSize: CGSize(width: limitWidth, height: limitWidth),
  1485. maxSizeInBytes: 1024 * 1024 * 5,
  1486. targetCompression: 1.0)
  1487. }
  1488. //自适应page
  1489. let pageRect = self.listView?.currentPage().bounds ?? .zero
  1490. if imageRect.width > pageRect.width ||
  1491. imageRect.height > pageRect.height {
  1492. let pageScale = min(pageRect.width / imageSize.width, pageRect.height / imageSize.height)
  1493. imageRect = CGRect(x: imageRect.origin.x,
  1494. y: imageRect.origin.y,
  1495. width: imageRect.width * pageScale,
  1496. height: imageRect.height * pageScale)
  1497. }
  1498. if imageRect.origin.x < 0 {
  1499. imageRect.origin.x = 5
  1500. }
  1501. if imageRect.origin.y < 0 {
  1502. imageRect.origin.y = 5
  1503. }
  1504. if imageRect.origin.x + imageRect.width > pageRect.width ||
  1505. imageRect.origin.y + imageRect.height > pageRect.height {
  1506. let offsetX = imageRect.origin.x + imageRect.width - pageRect.width
  1507. let offsetY = imageRect.origin.y + imageRect.height - pageRect.height
  1508. imageRect.origin.x = imageRect.origin.x - offsetX - 5
  1509. imageRect.origin.y = imageRect.origin.y - offsetY - 5
  1510. }
  1511. DispatchQueue.main.async {
  1512. self.listView?.createImagePath(filePath, rect: imageRect, page: pdfView.currentPage())
  1513. self.viewC?.model.isPDFTextImageEdited = true
  1514. self.viewC?.recordIsPDFDocumentEdited(type: .editImage)
  1515. self.showPopWindow(positionRect: imageRect, showGuide: true)
  1516. }
  1517. }
  1518. }
  1519. }
  1520. }
  1521. }
  1522. func pdfViewEditingAddTextArea(_ pdfView: CPDFView!, add page: CPDFPage!, add rect: CGRect) {
  1523. let window = KMEditPDFPopToolBarWindow.shared
  1524. if (window.isVisible) {
  1525. self.hiddenPopWindow()
  1526. let areas = self.listView?.editingAreas() as? [CPDFEditArea] ?? []
  1527. if let area = areas.last {
  1528. if let data = area as? CPDFEditTextArea {
  1529. if let str = data.editTextAreaString(), str.isEmpty {
  1530. self.listView?.remove(with: [area])
  1531. } else {
  1532. self.listView?.updateEditing([])
  1533. }
  1534. }
  1535. }
  1536. return
  1537. }
  1538. var newRect = rect
  1539. if rect.size.equalTo(.zero) {
  1540. newRect = CGRect(x: rect.origin.x, y: rect.origin.y - 12, width: 20, height: 12)
  1541. } else {
  1542. newRect = CGRect(x: rect.origin.x, y: rect.origin.y + rect.size.height - 12, width: rect.size.width, height: 12)
  1543. }
  1544. let model = KMEditPDFTextManager.manager.fetchUserDefaultData(type: .commonly)
  1545. // let fontName = KMEditPDFTextManager.manager.fetchFontName(fontName: model.fontName)
  1546. let fontSize = model.fontSize
  1547. let fontColor = model.color
  1548. let fontAlign = model.alignment
  1549. // let fontStyle = KMEditPDFTextManager.manager.fetchFontStyle(fontName: model.fontName)
  1550. NSColorPanel.shared.color = fontColor
  1551. // let font = KMEditPDFTextManager.manager.fetchFont(fontName: fontName, style: fontStyle, size: fontSize)
  1552. let cfont = CPDFFont(familyName: model.fontName, fontStyle: model.fontStyle)
  1553. let fontNameZ = CPDFFont.convertAppleFont(cfont)
  1554. let font = NSFont(name: fontNameZ ?? "Helvetica", size: fontSize)
  1555. let attri = CEditAttributes()
  1556. attri.font = font!
  1557. attri.fontColor = fontColor
  1558. attri.alignment = fontAlign
  1559. attri.isBold = model.bold
  1560. attri.isItalic = model.italic
  1561. self.addTextAreaing = true
  1562. self.listView?.createStringBounds(newRect, with: attri, page: page)
  1563. self.addTextAreaing = false
  1564. // self.rightViewC != nil &&
  1565. if self.subViewType == .EditPDFAddText && self.annotationType == .addText {
  1566. self.rightViewC?.eidtPDFTextProperty.handdler = self
  1567. self.rightViewC?.eidtPDFTextProperty.refreshSelectAreaProperty(needDefaultData: true)
  1568. }
  1569. self.showPopWindow(positionRect: newRect, showGuide: true)
  1570. }
  1571. // 文本区块 选中文本已经变化
  1572. func pdfViewEditingSelectionDidChanged(_ pdfView: CPDFView!) {
  1573. // self.viewC?.rightSideViewController != nil &&
  1574. if self.subViewType == .EditPDFAddText {
  1575. self.rightViewC?.eidtPDFTextProperty.handdler = self
  1576. self.rightViewC?.eidtPDFTextProperty.reloadData()
  1577. self.rightViewC?.eidtPDFTextProperty.updateTextTextPresuppositionState()
  1578. self.showPopWindow(positionRect: .zero, showGuide: false)
  1579. }
  1580. }
  1581. func pdfViewEditingOperationDidChanged(_ pdfView: CPDFView!) {
  1582. let areas = self.editingAreas
  1583. if areas.count == 1 {
  1584. if let data = areas.first as? CPDFEditImageArea {
  1585. let updating = self.listView?.editAreaBoundUpdating ?? false
  1586. if updating {
  1587. self.listView?.editAreaBoundUpdating = false
  1588. } else {
  1589. self.rightViewC?.eidtPDFImageProperty.handdler = self
  1590. self.rightViewC?.eidtPDFImageProperty.reloadData()
  1591. }
  1592. }
  1593. }
  1594. }
  1595. func pdfViewEditingDoubleClick(_ pdfView: CPDFView!, imageArea editArea: CPDFEditArea!) {
  1596. }
  1597. func pdfViewMobileEditingBegan(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) {
  1598. self.hiddenPopWindow()
  1599. }
  1600. func pdfViewMobileEditingMove(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) {
  1601. }
  1602. func pdfViewMobileEditingEnd(_ point: CGPoint, for pdfView: CPDFView!, forEditing editingAreas: [CPDFEditArea]!) {
  1603. self.showPopWindow(positionRect: .zero, showGuide: false)
  1604. }
  1605. func pdfViewEditingSelectCharDidChanged(_ pdfView: CPDFView!) {
  1606. let areas = self.editingTextAreas
  1607. if areas.isEmpty {
  1608. return
  1609. }
  1610. if self.subViewType == .EditPDFAddText {
  1611. // self.rightViewC?.eidtPDFTextProperty.reloadData()
  1612. // self.rightViewC?.eidtPDFTextProperty.updateTextTextPresuppositionState()
  1613. if self.addTextAreaing == false && self.fontSizeChanging == false && self.textAlignChanging == false {
  1614. self.showPopWindow(positionRect: .zero, showGuide: false)
  1615. self._reloadData_right_text()
  1616. }
  1617. }
  1618. }
  1619. func pdfViewEditingExitCropMode(_ pdfView: CPDFView!, forEditing editingArea: CPDFEditImageArea!) {
  1620. self.cropCancelAction()
  1621. }
  1622. }