// // KMSelfSignAnnotation.swift // PDF Reader Pro // // Created by lizhe on 2023/10/12. // import Quartz @objcMembers class KMSelfSignAnnotation: CPDFStampAnnotation { var annotationType: CAnnotationType = .unkown { didSet { let annotationModel: CPDFAnnotationModel = CPDFAnnotationModel(annotationType: annotationType) lineAnnotationWidth = annotationModel.lineWidth() lineOpacity = annotationModel.opacity() lineColor = annotationModel.color() updateAppearanceStream() } } var lineAnnotationWidth: CGFloat = 1.0 var lineOpacity: CGFloat = 1.0 var lineColor: NSColor = NSColor.black override init() { super.init() } func getBezierPathsArray() -> [NSBezierPath] { var lines = [NSBezierPath]() let bounds = self.bounds var bezierPath: NSBezierPath if self.annotationType == .signFalse { bezierPath = NSBezierPath() bezierPath.move(to: NSPoint(x: bounds.minX + self.lineAnnotationWidth, y: bounds.minY + self.lineAnnotationWidth)) bezierPath.line(to: NSPoint(x: bounds.maxX - self.lineAnnotationWidth, y: bounds.maxY - self.lineAnnotationWidth)) bezierPath.close() lines.append(bezierPath) bezierPath = NSBezierPath() bezierPath.move(to: NSPoint(x: bounds.minX + self.lineAnnotationWidth, y: bounds.maxY - self.lineAnnotationWidth)) bezierPath.line(to: NSPoint(x: bounds.maxX - self.lineAnnotationWidth, y: bounds.minY + self.lineAnnotationWidth)) bezierPath.close() lines.append(bezierPath) } else if self.annotationType == .signTure { bezierPath = NSBezierPath() bezierPath.move(to: NSPoint(x: bounds.minX + self.lineAnnotationWidth / 2.0, y: bounds.midY + self.lineAnnotationWidth / 2.0)) bezierPath.line(to: NSPoint(x: bounds.minX + bounds.width / 3.0, y: bounds.minY + self.lineAnnotationWidth / 2.0)) bezierPath.line(to: NSPoint(x: bounds.maxX - self.lineAnnotationWidth / 2.0, y: bounds.maxY - self.lineAnnotationWidth / 2.0)) lines.append(bezierPath) } else if self.annotationType == .signCircle { let r = min(bounds.width, bounds.height) / 3.0 bezierPath = NSBezierPath(roundedRect: bounds.insetBy(dx: self.lineAnnotationWidth / 2, dy: self.lineAnnotationWidth / 2), xRadius: r, yRadius: r) lines.append(bezierPath) bezierPath.close() } else if self.annotationType == .signLine { bezierPath = NSBezierPath() bezierPath.move(to: NSPoint(x: bounds.minX - 1, y: bounds.midY)) bezierPath.line(to: NSPoint(x: bounds.maxX - 2, y: bounds.midY)) bezierPath.close() lines.append(bezierPath) } return lines } func getBezierLinesArray() -> [[String]] { let lines = getBezierPathsArray() var bezierPaths = [[String]]() for bezierPath in lines { bezierPaths.append(bezierPath.getAllSignCirclePoint()) } return bezierPaths } override func updateAppearanceStream() { let color = self.lineColor var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 color.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) if self.annotationType == .signDot { let orgBounds = self.bounds let eProportion = min(orgBounds.size.width, orgBounds.size.height) let rect = NSRect(x: orgBounds.origin.x + (orgBounds.size.width - eProportion) / 2, y: orgBounds.origin.y + (orgBounds.size.height - eProportion) / 2, width: eProportion, height: eProportion) updateAppearanceStream(withArc: rect, border: 0, color: nil, fill: NSColor(red: red, green: green, blue: blue, alpha: self.lineOpacity)) } else { let lines = getBezierLinesArray() var paths = [[NSValue]]() for line in lines { var tPoints = [NSValue]() for value in line { let pointComponents = value.components(separatedBy: ",") if pointComponents.count == 2, let x = Double(pointComponents[0]), let y = Double(pointComponents[1]) { let point = NSPoint(x: x, y: y) tPoints.append(NSValue(point: point)) } } if tPoints.count > 0 { paths.append(tPoints) } } if paths.count > 0 { updateAppearanceStream(withPaths: paths, border: lineAnnotationWidth, color: NSColor(red: red, green: green, blue: blue, alpha: self.lineOpacity)) } } } func draw(with box: CPDFDisplayBox, inContext context: CGContext) { var pathColor = self.lineColor var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 0.0 pathColor.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) pathColor = NSColor(red: red, green: green, blue: blue, alpha: self.lineOpacity) if self.annotationType == .signTure || self.annotationType == .signFalse || self.annotationType == .signLine || self.annotationType == .signCircle { for bezierPath in getBezierPathsArray() { context.addPath(createCGPath(from: bezierPath)) } context.setLineWidth(lineAnnotationWidth) context.setStrokeColor(pathColor.cgColor) context.setFillColor(pathColor.cgColor) context.strokePath() } else if self.annotationType == .signDot { context.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1.0) context.setLineWidth(1.0) context.addArc(center: NSMakePoint(self.bounds.midX, self.bounds.midY), radius: min(self.bounds.width / 2.0 - 1, self.bounds.height / 2.0 - 1), startAngle: 0, endAngle: .pi * 2, clockwise: true) context.setStrokeColor(pathColor.cgColor) context.setFillColor(pathColor.cgColor) context.fillPath() } } func createCGPath(from bezierPath: NSBezierPath) -> CGPath { let path = CGMutablePath() let elementCount = bezierPath.elementCount var points = [NSPoint](repeating: .zero, count: 3) for i in 0.. NSColor { var color = NSColor.clear if type == .signDot { color = UserDefaults.standard.color(forKey: "SKAnnotationSelfSignDotColorKey") ?? NSColor.clear } else if type == .signLine { color = UserDefaults.standard.color(forKey: "SKAnnotationSelfSignLineColorKey") ?? NSColor.clear } else if type == .signCircle { color = UserDefaults.standard.color(forKey: "SKAnnotationSelfSignCircleColorKey") ?? NSColor.clear } else if type == .signFalse { color = UserDefaults.standard.color(forKey: "SKAnnotationSelfSignFalseColorKey") ?? NSColor.clear } else if type == .signTure { color = UserDefaults.standard.color(forKey: "SKAnnotationSelfSignTureColorKey") ?? NSColor.clear } return color } static func fetchStoredLineWidth(_ type: CAnnotationType) -> CGFloat { var rtnLineWidth: CGFloat = 0 if type == .signDot { rtnLineWidth = CGFloat(UserDefaults.standard.float(forKey: "SKAnnotationSelfSignDotLineWidthKey")) } else if type == .signLine { rtnLineWidth = CGFloat(UserDefaults.standard.float(forKey: "SKAnnotationSelfSignLineLineWidthKey")) } else if type == .signCircle { rtnLineWidth = CGFloat(UserDefaults.standard.float(forKey: "SKAnnotationSelfSignCircleLineWidthKey")) } else if type == .signFalse { rtnLineWidth = CGFloat(UserDefaults.standard.float(forKey: "SKAnnotationSelfSignTureLineWidthKey")) } else if type == .signTure { rtnLineWidth = CGFloat(UserDefaults.standard.float(forKey: "SKAnnotationSelfSignTureLineWidthKey")) } if rtnLineWidth == 0.0 { changeStoredLineWidth(type, lineWidth: 0.8) rtnLineWidth = 0.8 } return rtnLineWidth } // 修改缓存的颜色 static func changeStoredColor(_ type: CAnnotationType, color newColor: NSColor) { guard newColor.numberOfComponents > 0 else { return } let userDefaults = UserDefaults.standard if type == .signDot { userDefaults.setColor(newColor, forKey: "SKAnnotationSelfSignDotColorKey") } else if type == .signLine { userDefaults.setColor(newColor, forKey: "SKAnnotationSelfSignLineColorKey") } else if type == .signCircle { userDefaults.setColor(newColor, forKey: "SKAnnotationSelfSignCircleColorKey") } else if type == .signFalse { userDefaults.setColor(newColor, forKey: "SKAnnotationSelfSignFalseColorKey") } else if type == .signTure { userDefaults.setColor(newColor, forKey: "SKAnnotationSelfSignTrueColorKey") } } static func changeStoredLineWidth(_ type: CAnnotationType, lineWidth: CGFloat) { let userDefaults = UserDefaults.standard if type == .signDot { userDefaults.set(lineWidth, forKey: "SKAnnotationSelfSignDotLineWidthKey") } else if type == .signLine { userDefaults.set(lineWidth, forKey: "SKAnnotationSelfSignLineLineWidthKey") } else if type == .signCircle { userDefaults.set(lineWidth, forKey: "SKAnnotationSelfSignCircleLineWidthKey") } else if type == .signFalse { userDefaults.set(lineWidth, forKey: "SKAnnotationSelfSignFalseLineWidthKey") } else if type == .signTure { userDefaults.set(lineWidth, forKey: "SKAnnotationSelfSignTrueLineWidthKey") } } static func fetchSelfSignTypeString(_ type: CAnnotationType) -> String { var returnString = "" if type == .signFalse { returnString = NSLocalizedString("X", comment: "") } else if type == .signTure { returnString = NSLocalizedString("Check mark", comment: "") } else if type == .signCircle { returnString = NSLocalizedString("Circle", comment: "") } else if type == .signLine { returnString = NSLocalizedString("Line", comment: "") } else if type == .signDot { returnString = NSLocalizedString("Dot", comment: "") } return returnString } }