// // KMRedactPDFView.swift // PDF Reader Pro // // Created by tangchao on 2023/12/18. // import Cocoa enum KMPDFRedactViewOperationType: Int { case none = 0 //没有进入任何模式 case redact //标记密文模式 case editText //文本编辑 case redactWhite //密文标记涂白模式 } private let KMPDFViewShowCurrentRedactAnnotation = "KMPDFViewShowCurrentRedactAnnotation" private let KMPDFViewRedactAnnotationApply = "KMPDFViewRedactAnnotationApply" private let KMPDFViewRedactAnnotationAcross = "KMPDFViewRedactAnnotationAcross" class KMPDFWhiteOutRedactAnnotation: CPDFRedactAnnotation { } @objcMembers class KMRedactPDFView: CPDFListView { private let MIN_NOTE_SIZE: CGFloat = 8.0 static let showCurrentRedactAnnotationNotificationName = Notification.Name(KMPDFViewShowCurrentRedactAnnotation) static let redactAnnotationApplyNotificationName = Notification.Name(KMPDFViewRedactAnnotationApply) static let redactAnnotationAcrossNotificationName = Notification.Name(KMPDFViewRedactAnnotationAcross) var mouseMoveAnnotation: CPDFAnnotation? var currentAnnotation: CPDFRedactAnnotation? var newAddAnnotation: [CPDFAnnotation] = [] // var activeAnnotations: [CPDFAnnotation] = [] var operationType: KMPDFRedactViewOperationType = .none var isEidtImageModel = false var isEidtTextModel = false var isWhiteOut = false var eventColorChanged: ((NSColor)->Void)? var eventFontChanged: (()->Void)? var exportBtnTaped: ((Int)->Void)? private var _localMonitor: AnyObject? override init(frame frameRect: NSRect) { super.init(frame: frameRect) self.operationType = .none self.addTrackingArea() self.initMonitor() } required init?(coder: NSCoder) { super.init(coder: coder) self.operationType = .none self.addTrackingArea() self.initMonitor() } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Drawing code here. } func resignMonitor() { if let monitor = self._localMonitor { NSEvent.removeMonitor(monitor) self._localMonitor = nil } } func addTrackingArea() { self.newAddAnnotation = [] self.activeAnnotations = [] let trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .inVisibleRect, .activeInKeyWindow], owner: self) self.addTrackingArea(trackingArea) } func initMonitor() { let mask: NSEvent.EventTypeMask = .keyDown guard _localMonitor == nil else { return } _localMonitor = NSEvent.addLocalMonitorForEvents(matching: mask) { event in // 获取事件的第一个字符 let eventChar = event.PDFListViewFirstCharacter() // 获取标准的修饰符标志 let modifiers = Self.standardPDFListViewModifierFlags() // 获取当前响应者 if let currentResponder = NSApp.keyWindow?.firstResponder, !(currentResponder is NSTextView) { // 如果按下的是删除键,并且没有修饰符,则执行删除操作 if (eventChar == NSDeleteCharacter || eventChar == NSDeleteFunctionKey), modifiers == 0 { self.delete() } // 如果按下的是回车键,并且没有修饰符,则执行图像裁剪完成操作 if event.keyCode == 36, modifiers == 0 { self.corpImageDoneWithEnter() } } // 返回事件以继续处理 return event } as AnyObject? } override func menu(for event: NSEvent) -> NSMenu? { var menu = super.menu(for: event) // if (menu == nil) { menu = NSMenu() // } var pagePoint = NSZeroPoint // CPDFPage *page = [self pageAndPoint:&pagePoint forEvent:event nearest:YES]; let page = self.pageAndPoint(&pagePoint, for: event, nearest: true) // CPDFAnnotation *annotation = [page annotationAtPoint:pagePoint]; let annotation = page?.annotation(at: pagePoint) if let data = annotation, data is CPDFRedactAnnotation && (self.operationType == .redact || self.operationType == .redactWhite) { var item = menu?.insertItem(withTitle: KMLocalizedString("Delete", nil), action: #selector(deleteAnnotation), target: self, at: 0) item?.representedObject = annotation menu?.insertItem(.separator(), at: 1) item = menu?.insertItem(withTitle: KMLocalizedString("Make Current Properties Default", nil), action: #selector(setPropertiesDefault), target: self, at: 2) item?.representedObject = annotation _ = menu?.insertItem(withTitle: KMLocalizedString("Properties", nil), action: #selector(properties), target: self, at: 3) menu?.insertItem(.separator(), at: 4) _ = menu?.insertItem(withTitle: KMLocalizedString("Repeat Mark Across Pages", nil), action: #selector(repeatMark), target: self, at: 5) _ = menu?.insertItem(withTitle: KMLocalizedString("Apply Redactions", nil), action: #selector(applyRedact), target: self, at: 6) self.currentAnnotation = annotation as? CPDFRedactAnnotation } return menu } @objc func deleteAnnotation(_ sender: NSMenuItem?) { if let annotation = sender?.representedObject as? CPDFRedactAnnotation { self.remove(annotation) // removeAnnotation(annotation: annotation) } } func removeAnnotation(annotation: CPDFAnnotation) { let annos = NSMutableArray() annos.add(annotation) removeAccosAnnotations(annos) } @objc func setPropertiesDefault(_ sender: NSMenuItem?) { if let annotation = sender?.representedObject as? CPDFRedactAnnotation { KMPDFAnnotationRedactConfig.shared.redactOutlineColor = annotation.borderColor() KMPDFAnnotationRedactConfig.shared.redactFillColor = annotation.interiorColor() KMPDFAnnotationRedactConfig.shared.redactFontColor = annotation.fontColor() KMPDFAnnotationRedactConfig.shared.overlayText = annotation.overlayText().isEmpty == false KMPDFAnnotationRedactConfig.shared.fontSize = Int(annotation.font().pointSize) if annotation.alignment() == .left { KMPDFAnnotationRedactConfig.shared.textAlignment = 0 } else if annotation.alignment() == .center { KMPDFAnnotationRedactConfig.shared.textAlignment = 1 } else if annotation.alignment() == .right { KMPDFAnnotationRedactConfig.shared.textAlignment = 2 } KMPDFAnnotationRedactConfig.shared.overlayTextString = annotation.overlayText() } } @objc func properties() { NotificationCenter.default.post(name: Self.showCurrentRedactAnnotationNotificationName, object: self) } @objc func repeatMark() { NotificationCenter.default.post(name: Self.redactAnnotationAcrossNotificationName, object: self) } @objc func applyRedact() { NotificationCenter.default.post(name: Self.redactAnnotationApplyNotificationName, object: self) } /* - (CGSize)getWidthFromText:(NSString *)text WithSize:(NSFont *)font AboutWidth:(CGFloat)width AndHeight:(CGFloat)height { if (!text) { return CGSizeMake(0, 0); } CGRect rect = [text boundingRectWithSize:CGSizeMake(width, height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil]; return rect.size; } */ override func menuItemsEditing(at point: CGPoint, for page: CPDFPage!) -> [NSMenuItem]! { var menuItems = super.menuItemsEditing(at: point, for: page) if (menuItems == nil) { menuItems = [] } if self.isSelectEditCharRange() || self.isSelecteditArea(with: point) { menuItems?.insert(.separator(), at: 0) menuItems?.insert(self.fontColorMenuItem(), at: 0) menuItems?.insert(self.fontSizeMenuItem(), at: 0) } if self.editingArea() != nil { if self.editingArea().isImageArea() { menuItems?.insert(.separator(), at: 0) // // [menuItems insertObject:[self imageCutMenuItem] atIndex:0]; // // [menuItems insertObject:[self imagePasteMenuItem] atIndex:0]; // [menuItems insertObject:[self imageRotateMenuItem] atIndex:0]; menuItems?.insert(self.imageExportMenuItem(), at: 0) } } return menuItems } // MARK: - keyDown override func mouseMoved(with event: NSEvent) { self.window?.mouseMoved(with: event) super.mouseMoved(with: event) var continueAction = false if(self.operationType == .redact || self.operationType == .redactWhite) { continueAction = true } if continueAction == false { return } var pagePoint = NSZeroPoint var page = self.pageAndPoint(&pagePoint, for: event, nearest: true) var fromView: NSView? let newpoint = self.convert(event.locationInWindow, from: fromView) let area = self.areaOfInterest(for: newpoint) if area.contains(.textArea) { NSCursor.iBeam.set() }else{ NSCursor.arrow.set() } let newActiveAnnotation = page?.annotation(at: pagePoint) if newActiveAnnotation != nil && newActiveAnnotation is CPDFRedactAnnotation && self.mouseMoveAnnotation == newActiveAnnotation { // if newActiveAnnotation is KMPDFWhiteOutRedactAnnotation { // // } else { (newActiveAnnotation as? CPDFRedactAnnotation)?.drawRedactionsAsRedacted = true // } self.setNeedsDisplayAnnotationViewFor(page) } else if self.mouseMoveAnnotation != nil && self.mouseMoveAnnotation is CPDFRedactAnnotation { // if self.mouseMoveAnnotation is KMPDFWhiteOutRedactAnnotation { // // } else { (self.mouseMoveAnnotation as? CPDFRedactAnnotation)?.drawRedactionsAsRedacted = false // } self.setNeedsDisplayAnnotationViewFor(page) } self.mouseMoveAnnotation = newActiveAnnotation } override func mouseDown(with event: NSEvent) { var pagePoint = NSZeroPoint var continueAction = false if(self.operationType == .redact || self.operationType == .redactWhite) { continueAction = true } if continueAction == false { return } var page = self.pageAndPoint(&pagePoint, for: event, nearest: true) let newActiveAnnotation = page?.annotation(at: pagePoint) var fromView: NSView? let newpoint = self.convert(event.locationInWindow, from: fromView) let area = self.areaOfInterest(for: newpoint) self.activeAnnotations.removeAllObjects() //预留 if(newActiveAnnotation != nil) { if self.activeAnnotations.contains(newActiveAnnotation!) == false { self.activeAnnotations.add(newActiveAnnotation!) } self.setNeedsDisplayAnnotationViewFor(page) _ = self.doDragMouse(event: event) } else if area.contains(.textArea) { super.mouseDown(with: event) self.doMarkUp(event: event) self.currentSelection = nil } else { self.doRedact(event: event) } } func delete() { for anno in self.activeAnnotations { if anno is CPDFRedactAnnotation { self.remove(anno as? CPDFAnnotation) } } } func corpImageDoneWithEnter() { // if([self.editingArea isKindOfClass:[CPDFEditImageArea class]]) { // CPDFEditImageArea *editImageArea = (CPDFEditImageArea *)self.editingArea; // if(editImageArea.isCropMode) { // [self cropEditImageArea:editImageArea withBounds:editImageArea.cropRect]; // [self exitCropWithEditImageArea:editImageArea]; // } // } } // MARK: - Rendering func doDragMouse(event: NSEvent) -> Bool { var didDrag = false while (true) { if self.window?.nextEvent(matching: [.leftMouseUp, .leftMouseDragged])?.type == .leftMouseUp { break } didDrag = true } return didDrag } func doMarkUp(event: NSEvent) { let eventMask: NSEvent.EventTypeMask = [.leftMouseUp, .leftMouseDragged] var theEvent: NSEvent = event while (true) { theEvent = self.window!.nextEvent(matching: eventMask)! if theEvent.type == .leftMouseUp { if (self.currentSelection != nil) { let page = self.currentSelection.page var annotation = self.addRedactPDFSelection(self.currentSelection) // if self.isWhiteOut { // annotation = self.addWhiteRedactPDFSelection(self.currentSelection) // } annotation?.setModificationDate(Date()) let userName = KMPreference.shared.author annotation?.setUserName(userName) annotation?.borderWidth = 1 if self.operationType == .redact { annotation?.setBorderColor(KMPDFAnnotationRedactConfig.shared.redactOutlineColor) annotation?.setInteriorColor(KMPDFAnnotationRedactConfig.shared.redactFillColor) annotation?.setFontColor(KMPDFAnnotationRedactConfig.shared.redactFontColor) if KMPDFAnnotationRedactConfig.shared.overlayText { if KMPDFAnnotationRedactConfig.shared.textAlignment == 0 { annotation?.setAlignment(.left) } else if KMPDFAnnotationRedactConfig.shared.textAlignment == 1 { annotation?.setAlignment(.center) } else if KMPDFAnnotationRedactConfig.shared.textAlignment == 2 { annotation?.setAlignment(.right) } let font = NSFont(name: "Helvetica", size: KMPDFAnnotationRedactConfig.shared.fontSize.cgFloat) annotation?.setFont(font) annotation?.setOverlayText(KMPDFAnnotationRedactConfig.shared.overlayTextString) } } else if self.operationType == .redactWhite { annotation?.setBorderColor(NSColor.red) annotation?.setInteriorColor(NSColor.white) annotation?.setFontColor(NSColor.white) } self.addAnnotation(with: annotation, to: page) self.newAddAnnotation.append(annotation!) self.setNeedsDisplayFor(page) } break } else if theEvent.type == .leftMouseDragged { super.mouseDragged(with: theEvent) } } } func doRedact(event: NSEvent) { var point = NSZeroPoint let page = self.pageAndPoint(&point, for: event, nearest: true) let wasMouseCoalescingEnabled = NSEvent.isMouseCoalescingEnabled let window = self.window var bezierPath: NSBezierPath? var layer: CAShapeLayer? let boxBounds = page?.bounds ?? .zero let t = CGAffineTransform(scaleX: self.scaleFactor, y: self.scaleFactor).rotated(by: -Double.pi * 0.5 * (page!.rotation.cgFloat / 90.0)) layer = CAShapeLayer() layer?.bounds = NSRectToCGRect(boxBounds) layer?.anchorPoint = .zero let posi = self.convert(boxBounds.origin, from: page) layer?.position = NSPointToCGPoint(posi) layer?.setAffineTransform(t) layer?.zPosition = 1.0 layer?.masksToBounds = true if self.operationType == .redact { layer?.fillColor = KMPDFAnnotationRedactConfig.shared.redactFillColor?.cgColor // layer?.strokeColor = .black } else if self.operationType == .redactWhite { layer?.fillColor = .white layer?.strokeColor = .white } // layer?.strokeColor = CGColorGetConstantColor(kCGColorBlack) layer?.lineJoin = .round layer?.lineCap = .round var lastMouseEvent = event // SKRectEdges var resizeHandle: CRectEdges = [.minYEdgeMask, .maxXEdgeMask] var originalBounds = NSMakeRect(point.x, point.y, 0, 0) self.layer?.addSublayer(layer!) var eventMask: NSEvent.EventTypeMask = [.leftMouseUp, .leftMouseDragged] var rect = NSRect.zero var theEvent = event while (true) { theEvent = window!.nextEvent(matching: eventMask)! if theEvent.type == .leftMouseUp { if (rect.size.width < MIN_NOTE_SIZE || rect.size.height < MIN_NOTE_SIZE) { break } var quadrilateralPoints = NSMutableArray() var annotation = CPDFRedactAnnotation(document: self.document) // if self.isWhiteOut { // annotation = KMPDFWhiteOutRedactAnnotation(document: self.document) // } var bounds = rect quadrilateralPoints.add(NSValue(point: NSMakePoint(NSMinX(bounds), NSMaxY(bounds)))) quadrilateralPoints.add(NSValue(point: NSMakePoint(NSMaxX(bounds), NSMaxY(bounds)))) quadrilateralPoints.add(NSValue(point: NSMakePoint(NSMinX(bounds), NSMinY(bounds)))) quadrilateralPoints.add(NSValue(point: NSMakePoint(NSMaxX(bounds), NSMinY(bounds)))) annotation?.setQuadrilateralPoints(quadrilateralPoints as? [Any] ?? []) annotation?.setModificationDate(Date()) let userName = KMPreference.shared.author annotation?.setUserName(userName) // if ([annotation isKindOfClass:[CPDFRedactAnnotation class]]) { annotation?.borderWidth = 1 if self.operationType == .redact { annotation?.setBorderColor(KMPDFAnnotationRedactConfig.shared.redactOutlineColor) annotation?.setInteriorColor(KMPDFAnnotationRedactConfig.shared.redactFillColor) annotation?.setFontColor(KMPDFAnnotationRedactConfig.shared.redactFontColor) if KMPDFAnnotationRedactConfig.shared.overlayText { if KMPDFAnnotationRedactConfig.shared.textAlignment == 0 { annotation?.setAlignment(.left) } else if KMPDFAnnotationRedactConfig.shared.textAlignment == 1 { annotation?.setAlignment(.center) } else if KMPDFAnnotationRedactConfig.shared.textAlignment == 2 { annotation?.setAlignment(.right) } let font = NSFont(name: "Helvetica", size: KMPDFAnnotationRedactConfig.shared.fontSize.cgFloat) annotation?.setFont(font) annotation?.setOverlayText(KMPDFAnnotationRedactConfig.shared.overlayTextString) } } else if self.operationType == .redactWhite { annotation?.setBorderColor(NSColor.red) annotation?.setInteriorColor(NSColor.white) annotation?.setFontColor(NSColor.white) } // if self.isWhiteOut { // annotation?.drawRedactionsAsRedacted = false // } else { annotation?.drawRedactionsAsRedacted = false // } self.addAnnotation(with: annotation, to: page) self.newAddAnnotation.append(annotation!) break } else if theEvent.type == .leftMouseDragged { // rect = self.doResizeLink(event: lastMouseEvent, fromPoint: point, originalBounds: originalBounds, page: page!, resizeHandle: &resizeHandle) rect = self.doResizeLink(with: lastMouseEvent, from: point, originalBounds: originalBounds, page: page, resizeHandle: &resizeHandle) bezierPath = NSBezierPath(rect: rect) layer?.path = bezierPath?.kmCGPath() lastMouseEvent = theEvent } } layer?.removeFromSuperlayer() NSEvent.isMouseCoalescingEnabled = wasMouseCoalescingEnabled } func doResizeLink(event: NSEvent, fromPoint originalPagePoint: NSPoint, originalBounds: NSRect, page: CPDFPage, resizeHandle resizeHandlePtr: inout CRectEdges) -> NSRect { let currentPagePoint = self.convert(event.locationInView(self), to: page) var newBounds = originalBounds var pageBounds = page.bounds var relPoint = CPDFListViewSubstractPoints(currentPagePoint, originalPagePoint) var resizeHandle = resizeHandlePtr if (NSEqualSizes(originalBounds.size, NSZeroSize)) { var currentResizeHandle: CRectEdges = .minYEdgeMask if relPoint.x < 0.0 { currentResizeHandle = [.minXEdgeMask] } else { currentResizeHandle = [.maxXEdgeMask] } if relPoint.y <= 0.0 { currentResizeHandle.insert(.minYEdgeMask) } else { currentResizeHandle.insert(.maxYEdgeMask) } if (currentResizeHandle != resizeHandle) { resizeHandlePtr = currentResizeHandle resizeHandle = currentResizeHandle } } let minWidth = MIN_NOTE_SIZE let minHeight = MIN_NOTE_SIZE if resizeHandle.contains(.maxXEdgeMask) { newBounds.size.width += relPoint.x if (NSMaxX(newBounds) > NSMaxX(pageBounds)) { newBounds.size.width = NSMaxX(pageBounds) - NSMinX(newBounds) } if (NSWidth(newBounds) < minWidth) { newBounds.size.width = minWidth } } else if resizeHandle.contains(.minXEdgeMask) { newBounds.origin.x += relPoint.x newBounds.size.width -= relPoint.x if (NSMinX(newBounds) < NSMinX(pageBounds)) { newBounds.size.width = NSMaxX(newBounds) - NSMinX(pageBounds) newBounds.origin.x = NSMinX(pageBounds) } if (NSWidth(newBounds) < minWidth) { newBounds.origin.x = NSMaxX(newBounds) - minWidth newBounds.size.width = minWidth } } if resizeHandle.contains(.maxXEdgeMask) { newBounds.size.height += relPoint.y if (NSMaxY(newBounds) > NSMaxY(pageBounds)) { newBounds.size.height = NSMaxY(pageBounds) - NSMinY(newBounds) } if (NSHeight(newBounds) < minHeight) { newBounds.size.height = minHeight } } else if resizeHandle.contains(.minYEdgeMask) { newBounds.origin.y += relPoint.y newBounds.size.height -= relPoint.y if (NSMinY(newBounds) < NSMinY(pageBounds)) { newBounds.size.height = NSMaxY(newBounds) - NSMinY(pageBounds) newBounds.origin.y = NSMinY(pageBounds) } if (NSHeight(newBounds) < minHeight) { newBounds.origin.y = NSMaxY(newBounds) - minHeight newBounds.size.height = minHeight } } return newBounds } override func validate(_ menuItem: NSMenuItem!) -> Bool { guard let _doc = self.document, _doc.isLocked == false else { return false } let action = menuItem.action if (action == #selector(deleteAnnotation)) { return true } else if (action == #selector(setPropertiesDefault)) { return true } else if (action == #selector(properties)) { return true } else if (action == #selector(repeatMark)) { if(_doc.pageCount == 1) { return false } return true } else if (action == #selector(applyRedact)) { return true } else { return super.validate(menuItem) } } /* #pragma mark - - (void)drawPage:(CPDFPage *)page toContext:(CGContextRef)context { [self.activeAnnotations enumerateObjectsUsingBlock:^(CPDFAnnotation *annotation, NSUInteger idx, BOOL * _Nonnull stop) { if (annotation.page && [annotation.page isEqual:page]) { [annotation drawSelectionHighlightForView:self inContext:context]; } }]; } - (CPDFPage *)pageAndPoint:(NSPoint *)point forEvent:(NSEvent *)event nearest:(BOOL)nearest { NSPoint p = [event locationInView:self]; CPDFPage *page = [self pageForPoint:p nearest:nearest]; if (page && point) *point = [self convertPoint:p toPage:page]; return page; } */ } // MARK: - KMExtensions extension KMRedactPDFView { @objc dynamic func acrossAddAnnotations(_ pages: NSMutableArray) { if(pages.count == 0) { return } var anntations = NSMutableArray() for i in 0 ..< pages.count { // NSUInteger index = [[pages objectAtIndex:i] integerValue]; guard let index = (pages.object(at: i) as? NSNumber)?.intValue else { continue } if(index - 1 < self.document.pageCount) { // CPDFPage *page = [[self.document pageAtIndex:index-1] retain]; let page = self.document.page(at: UInt(index-1)) var annotation = CPDFRedactAnnotation(document: self.document) // if self.isWhiteOut { // annotation = KMPDFWhiteOutRedactAnnotation(document: self.document) // } if let anno = self.currentAnnotation { annotation?.setUserName(anno.userName()) annotation?.setModificationDate(anno.modificationDate()) annotation?.setQuadrilateralPoints(anno.quadrilateralPoints()) annotation?.borderWidth = anno.borderWidth if self.isWhiteOut { annotation?.setBorderColor(.white) annotation?.setInteriorColor(.white) } else { annotation?.setBorderColor(anno.borderColor()) annotation?.setInteriorColor(anno.interiorColor()) } annotation?.setFont(anno.font()) annotation?.setOverlayText(anno.overlayText()) annotation?.setFontColor(anno.fontColor()) annotation?.setAlignment(anno.alignment()) let pageRect = page?.bounds ?? .zero let annotationRect = annotation?.bounds ?? .zero if (NSMaxX(annotationRect) > NSMaxX(pageRect) || NSMinX(annotationRect) < NSMinX(pageRect) || NSMinY(annotationRect) < NSMinY(pageRect) || NSMaxY(annotationRect) > NSMaxY(pageRect) || anno.page == page){ continue } } page?.addAnnotation(annotation) anntations.add(annotation as Any) self.setNeedsDisplayAnnotationViewFor(page) } } (self.undoManager?.prepare(withInvocationTarget: self) as AnyObject).removeAccosAnnotations(anntations) } @objc dynamic func removeAccosAnnotations(_ annotations: NSMutableArray) { if(annotations.count == 0){ return } var pageIndexs = NSMutableArray() for i in 0 ..< annotations.count { guard let annotation = annotations.object(at: i) as? CPDFRedactAnnotation else { continue } let page = annotation.page let index = self.document.index(for: page) page?.removeAnnotation(annotation) pageIndexs.add(NSNumber(integerLiteral: Int(index)+1)) self.setNeedsDisplayAnnotationViewFor(page) } (self.undoManager?.prepare(withInvocationTarget: self) as AnyObject).acrossAddAnnotations(pageIndexs) } /* - (CGFloat)unitWidthOnPage:(CPDFPage *)page { return NSWidth([self convertRect:NSMakeRect(0.0, 0.0, 1.0, 1.0) toPage:page]); } - (NSRect)integralRect:(NSRect)rect onPage:(CPDFPage *)page { return [self convertRect:[self convertRect:rect fromPage:page] toPage:page]; } - (CPDFAnnotation *)addRedactPDFSelection:(CPDFSelection *)currentSelection { NSMutableArray *quadrilateralPoints = [NSMutableArray array]; CPDFRedactAnnotation *annotation = [[CPDFRedactAnnotation alloc] initWithDocument:self.document]; for (CPDFSelection *selection in currentSelection.selectionsByLine) { CGRect bounds = selection.bounds; [quadrilateralPoints addObject:[NSValue valueWithPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithPoint:CGPointMake(CGRectGetMinX(bounds), CGRectGetMinY(bounds))]]; [quadrilateralPoints addObject:[NSValue valueWithPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMinY(bounds))]]; } NSString *userName = [[NSUserDefaults standardUserDefaults] stringForKey:@"SKUserName"]; [annotation setUserName:userName ? : NSFullUserName()]; [annotation setModificationDate:[NSDate date]]; [annotation setQuadrilateralPoints:quadrilateralPoints]; [annotation setBorderWidth:10]; [(CPDFRedactAnnotation *)annotation setBorderColor:[KMPDFAnnotationRedactConfig sharedInstance].redactOutlineColor]; [(CPDFRedactAnnotation *)annotation setInteriorColor:[KMPDFAnnotationRedactConfig sharedInstance].redactFillColor]; [(CPDFRedactAnnotation *)annotation setFontColor:[KMPDFAnnotationRedactConfig sharedInstance].redactFontColor]; if([KMPDFAnnotationRedactConfig sharedInstance].overlayText) { [(CPDFRedactAnnotation *)annotation setAlignment:[KMPDFAnnotationRedactConfig sharedInstance].textAlignment]; NSFont* font = [NSFont fontWithName:@"Helvetica" size:[KMPDFAnnotationRedactConfig sharedInstance].fontSize]; [(CPDFRedactAnnotation *)annotation setFont:font]; [(CPDFRedactAnnotation *)annotation setOverlayText:[KMPDFAnnotationRedactConfig sharedInstance].overlayTextString]; } return annotation; } - (void)deleteAnnotation:(NSMenuItem *)item { CPDFRedactAnnotation *annotation = item.representedObject; if(annotation && [annotation isKindOfClass:[CPDFRedactAnnotation class]]) { [annotation retain]; CPDFPage *page = [[annotation page] retain]; [self setNeedsDisplayAnnotationViewForPage:page]; [self removeAnnotation:annotation]; [annotation release]; [page release]; } } - (void)addAnnotation:(CPDFAnnotation *)annotation toPage:(CPDFPage *)page { [[[self undoManager] prepareWithInvocationTarget:self] removeAnnotation:annotation]; [page addAnnotation:annotation]; if([self.newAddAnnotation containsObject:annotation]) { [self.newAddAnnotation removeObject:annotation]; } else { [self.newAddAnnotation addObject:annotation]; } [self setNeedsDisplayAnnotationViewForPage:page]; } - (void)removeAnnotation:(CPDFAnnotation *)annotation { CPDFAnnotation *wasAnnotation = [annotation retain]; CPDFPage *page = [[wasAnnotation page] retain]; [[[self undoManager] prepareWithInvocationTarget:self] addAnnotation:wasAnnotation toPage:page]; if([self.newAddAnnotation containsObject:annotation]) { [self.newAddAnnotation removeObject:annotation]; } else { [self.newAddAnnotation addObject:annotation]; } if([self.activeAnnotations containsObject:annotation]) { [self.activeAnnotations removeObject:annotation]; } [self setNeedsDisplayAnnotationViewForPage:page]; [page removeAnnotation:wasAnnotation]; [wasAnnotation release]; [page release]; } */ } // MARK: - Event extension KMRedactPDFView { func fontColorMenuItem() -> NSMenuItem { let fontColorItem = NSMenuItem(title: KMLocalizedString("Text Color", nil), action: #selector(menuItemEditingClick_FontColor), keyEquivalent: "") fontColorItem.target = self return fontColorItem } @objc func menuItemEditingClick_FontColor(_ sender: NSMenuItem?) { let color = self.editingSelectionFontColor() let cp = NSColorPanel.shared cp.orderFront(nil) cp.setTarget(self) cp.color = color! cp.showsAlpha = false cp.setAction(#selector(fontColorChangeAction)) } @objc func fontColorChangeAction(_ sender: AnyObject?) { self.setEditingSelectionFontColor(NSColorPanel.shared.color) guard let callback = self.eventColorChanged else { return } callback(NSColorPanel.shared.color) } func fontSizeMenuItem() -> NSMenuItem { let size = self.editingSelectionFontSize() let fontSizes = self.fontSizes() let submenu = NSMenu() for (i,fontSize) in fontSizes.enumerated() { let fs: CGFloat = fontSize.stringToCGFloat() let item = NSMenuItem(title: String(format: "%d pt", fs), action: #selector(menuItemEditingClick_FontSize), keyEquivalent: "") item.target = self item.tag = i submenu.addItem(item) if (fabsf(Float(fs-size)) < 0.1) { item.state = .on } } let fontSizeItem = NSMenuItem(title: KMLocalizedString("Font Size", nil), action: nil, keyEquivalent: "") fontSizeItem.submenu = submenu return fontSizeItem } func fontSizes() -> [String] { return ["6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "24", "36", "48", "72", "96", "144", "288"] } @objc func menuItemEditingClick_FontSize(_ item: NSMenuItem) { let fontSize = self.fontSizes()[item.tag].stringToCGFloat() self.setEditingSelectionFontSize(fontSize) guard let callback = self.eventFontChanged else { return } callback() } func imageExportMenuItem() -> NSMenuItem { let submenu = NSMenu() for (i, title) in self.titles().enumerated() { let item = NSMenuItem(title: title, action: #selector(menuItemEditingClick_export), keyEquivalent: "") item.tag = i submenu.addItem(item) } let exportmentItem = NSMenuItem(title: KMLocalizedString("Export", nil), action: nil, keyEquivalent: "") exportmentItem.submenu = submenu return exportmentItem } func titles() -> [String] { return ["PNG", "JPG", "PDF"] } @objc func menuItemEditingClick_export(_ item: NSMenuItem) { let idx = item.tag guard let callback = self.exportBtnTaped else { return } callback(idx) } func imageRotateMenuItem() -> NSMenuItem { let item = NSMenuItem(title: KMLocalizedString("Rotate", nil), action: #selector(menuItemEditingClick_RotateImage), keyEquivalent: "") item.target = self return item } @objc func menuItemEditingClick_RotateImage(_ iten: NSMenuItem) { self.rotate(with: self.editingArea() as? CPDFEditImageArea, rotate: 90) } /* - (NSMenuItem *)alightMenuItem { NSMenu *submenu = [[[NSMenu alloc] init] autorelease]; NSArray *titles = @[NSLocalizedString(@"Left Alignment", nil), NSLocalizedString(@"Right Alignment", nil), NSLocalizedString(@"Center", nil), NSLocalizedString(@"Justified Alignment", nil),]; NSTextAlignment alignment = [self editingSelectionAlignment]; for (NSUInteger i=0; i