KMEditPDfHanddler.swift 69 KB

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