// // KMWatermarkModel.swift // PDF Reader Pro // // Created by tangchao on 2022/12/19. // import Cocoa @objcMembers class KMWatermarkModel: KMWatermarkAdjectiveBaseModel { var text: String = NSLocalizedString("Watermark", comment: "") var image: NSImage! var imagePath: String = "" var textAligement: NSTextAlignment = .left var rotation: CGFloat = 0.0 var opacity: CGFloat = 1.0 var scale: CGFloat = 1.0 /** (Top:0 Middle:1 Bottom:2) */ var verticalMode: Int = 1 var verticalSpace: CGFloat = 0.0 /** (Left:0 Middle:1 Right:2) */ var horizontalMode: Int = 1 var horizontalSpace: CGFloat = 0.0 var tileHorizontalSpace: CGFloat = 60 var tileVerticalSpace: CGFloat = 60 var pagesString: String = "" var isFront: Bool = true var isTilePage: Bool = false var tag: String = "" var creatTemplateDate: String = "" var watermark: CPDFWatermark! var watermarkID: String = "" override func copy() -> Any { let model = KMWatermarkModel() model.text = self.text model.image = self.image model.imagePath = self.imagePath model.textColor = self.textColor model.textFont = self.textFont model.rotation = self.rotation model.opacity = self.opacity model.scale = self.scale model.verticalMode = self.verticalMode model.verticalSpace = self.verticalSpace model.horizontalMode = self.horizontalMode model.horizontalSpace = self.horizontalSpace model.tileHorizontalSpace = self.tileHorizontalSpace model.tileVerticalSpace = self.tileVerticalSpace model.pagesString = self.pagesString model.isFront = self.isFront model.isTilePage = self.isTilePage model.tag = self.tag model.pageRangeType = self.pageRangeType model.creatTemplateDate = self.creatTemplateDate model.watermark = self.watermark model.watermarkID = self.watermarkID return model } func updateData(document: CPDFDocument) { if (self.watermark == nil) { var scale: CGFloat = self.scale if (!self.text.isEmpty) { self.watermark = CPDFWatermark(document: document, type: .text) self.watermark.text = self.text self.watermark.textColor = self.getTextColor() scale = self.getTextFont().pointSize / 24.0 } else { self.watermark = CPDFWatermark(document: document, type: .image) self.watermark.image = self.image } } else { if (!self.text.isEmpty) { self.watermark.text = self.text self.watermark.textColor = self.getTextColor() scale = self.getTextFont().pointSize / 24.0 } else { self.watermark.image = self.image } } self.watermark.scale = scale self.watermark.rotation = -self.rotation self.watermark.opacity = self.opacity self.watermark.tx = self.horizontalSpace self.watermark.ty = self.verticalSpace self.watermark.isFront = self.isFront self.watermark.pageString = self.pagesString self.watermark.isTilePage = self.isTilePage self.watermark.horizontalSpacing = self.tileHorizontalSpace / scale self.watermark.verticalSpacing = self.tileVerticalSpace / scale if (self.verticalMode == 0) { self.watermark.verticalPosition = .top } else if (self.verticalMode == 1) { self.watermark.verticalPosition = .center } else if (self.verticalMode == 2) { self.watermark.verticalPosition = .bottom } if (self.horizontalMode == 0) { self.watermark.horizontalPosition = .left } else if (self.horizontalMode == 1) { self.watermark.horizontalPosition = .center } else if (self.horizontalMode == 2) { self.watermark.horizontalPosition = .right } } func drawImage(rect: CGRect) -> NSImage { var size: NSSize = NSZeroSize var drawRect: CGRect = NSMakeRect(0, 0, 128, 160) if (!self.text.isEmpty) { var font = NSFont.systemFont(ofSize: 48) if (self.isTilePage) { font = self.getTextFont() } var style = NSMutableParagraphStyle() style.alignment = self.textAligement style.lineBreakMode = .byCharWrapping let dictionary = [NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.font : font] size = self.text.boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: dictionary).size } else if (self.image != nil) { size = self.image.size size.width = size.width * self.scale size.height = size.height * self.scale } let radian = self.rotation * (Double.pi/180.0) let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian) if (!self.isTilePage) { drawRect = NSMakeRect(0, 0, size.width+40, size.height+40).applying(t); } let image = NSImage(size: drawRect.size) image.lockFocus() NSGraphicsContext.current?.imageInterpolation = .high NSGraphicsContext.saveGraphicsState() NSColor.clear.set() drawRect.fill() NSGraphicsContext.restoreGraphicsState() let context: CGContext = NSGraphicsContext.current!.cgContext let imageSize: NSSize = NSMakeSize(drawRect.size.width, drawRect.size.height) if (context != nil) { NSGraphicsContext.current = NSGraphicsContext(cgContext: context, flipped: false) } NSGraphicsContext.saveGraphicsState() if (!self.text.isEmpty) { var font = NSFont.systemFont(ofSize: 48) if (self.isTilePage) { font = self.getTextFont() } var color = NSColor.black if (self.textColor != nil) { color = self.getTextColor() } var red: CGFloat = 0 var green: CGFloat = 0 var blue: CGFloat = 0 color.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil) color = NSColor(calibratedRed: red, green: green, blue: blue, alpha: 1.0) var size = NSZeroSize let style = NSMutableParagraphStyle() style.alignment = self.textAligement style.lineBreakMode = .byCharWrapping let dictionary = [NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.foregroundColor : color, NSAttributedString.Key.font : font] size = self.text.boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: dictionary).size let radian: CGFloat = self.rotation * (Double.pi / 180.0) let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian) var textRect = NSMakeRect(0, 0, size.width, size.height).applying(t) if (self.isTilePage) { let width = sqrt(image.size.height * image.size.height + image.size.width * image.size.width) let newRect = NSMakeRect(-(width - image.size.width)/2, -(width - image.size.height)/2, width, width) let new_w = NSWidth(newRect) let new_h = NSHeight(newRect) context.translateBy(x: image.size.width/2,y: image.size.height/2); context.concatenate(t); context.translateBy(x: -(image.size.width/2), y: -(image.size.height/2)); let verticalWidth: CGFloat = size.width + self.tileHorizontalSpace/3.0 let horizontalHeight: CGFloat = size.height + self.tileVerticalSpace/3.0 let line: Int = Int(((new_h - self.tileHorizontalSpace/3.0)/horizontalHeight) + 1) let row: Int = Int((new_w - self.tileVerticalSpace/3.0) / verticalWidth + 1) let point = NSPoint(x: image.size.width/2 - size.width/2+self.horizontalSpace/3.0, y: image.size.height/2 - size.height/2+self.verticalSpace/3.0) for i in 0 ..< line { for j in 0 ..< row { self.text.draw(in: NSRect(x: point.x+CGFloat(j)*verticalWidth, y: point.y+CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary) } } for i in 1 ..< line { for j in 0 ..< row { self.text.draw(in: NSRect(x: point.x+CGFloat(j)*verticalWidth, y: point.y-CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary) } } for i in 0 ..< line { for j in 1 ..< row { self.text.draw(in: NSRect(x: point.x-CGFloat(j)*verticalWidth, y: point.y+CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary) } } for i in 1 ..< line { for j in 1 ..< row { self.text.draw(in: NSRect(x: point.x-CGFloat(j)*verticalWidth, y: point.y-CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary) } } } else { if (self.verticalMode == 0) { textRect.origin.y = imageSize.height-textRect.size.height } else if (self.verticalMode == 1) { textRect.origin.y = (imageSize.height-textRect.size.height) * 0.5 } else { textRect.origin.y = 0 } if (self.horizontalMode == 0) { textRect.origin.x = 0 } else if (self.horizontalMode == 1) { textRect.origin.x = (imageSize.width-textRect.size.width) * 0.5 } else { textRect.origin.x = imageSize.width-textRect.size.width } textRect.origin.x += self.horizontalSpace textRect.origin.y += self.verticalSpace let contextCenter = CGPoint(x: textRect.midX, y: textRect.midY) context.translateBy(x: contextCenter.x, y: contextCenter.y) context.rotate(by: radian) context.translateBy(x: -contextCenter.x, y: -contextCenter.y) let testRect = NSMakeRect(textRect.origin.x+(textRect.size.width-size.width)/2.0, textRect.origin.y+(textRect.size.height-size.height)/2.0, size.width, size.height) self.text.draw(in: NSMakeRect(textRect.origin.x+(textRect.size.width-size.width)/2.0, textRect.origin.y+(textRect.size.height-size.height)/2.0, size.width, size.height), withAttributes: dictionary) } } else if (self.image != nil) { var size = self.image.size size.width *= self.scale size.height *= self.scale let width: CGFloat = sqrt(image.size.height * image.size.height + image.size.width * image.size.width) let newRect = NSMakeRect(-(width - image.size.width)/2, -(width - image.size.height)/2, width, width) let new_w = newRect.size.width let new_h = newRect.size.height let radian: CGFloat = self.rotation * (Double.pi / 180.0) let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian) if (self.isTilePage) { context.translateBy(x: image.size.width/2,y: image.size.height/2) context.concatenate(t) context.translateBy(x: -(image.size.width/2), y: -(image.size.height/2)) let verticalWidth: CGFloat = size.width + self.tileHorizontalSpace * self.scale let horizontalHeight: CGFloat = size.height + self.tileVerticalSpace * self.scale let line: Int = Int((new_h - self.tileVerticalSpace * self.scale) / horizontalHeight + 1) let row: Int = Int((new_w - self.tileHorizontalSpace * self.scale) / verticalWidth + 1) let point = NSPoint(x: image.size.width/2 - size.width/2+self.horizontalSpace*self.scale, y: image.size.height/2 - size.height/2+self.verticalSpace * self.scale) for i in 0 ..< (line/2+1) { for j in 0 ..< row { let area = CGRect(x: point.x + CGFloat(j) * verticalWidth, y: point.y + CGFloat(i)*horizontalHeight, width: size.width, height: size.height) self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity) } } for i in 1 ..< (line/2+1) { for j in 0 ..< row { let area = CGRect(x: point.x + CGFloat(j) * verticalWidth, y: point.y - CGFloat(i)*horizontalHeight, width: size.width, height: size.height) self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity) } } for i in 0 ..< (line/2+1) { for j in 1 ..< row { let area = CGRect(x: point.x - CGFloat(j) * verticalWidth, y: point.y + CGFloat(i)*horizontalHeight, width: size.width, height: size.height) self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity) } } for i in 1 ..< (line/2+1) { for j in 1 ..< row { let area = CGRect(x: point.x - CGFloat(j) * verticalWidth, y: point.y - CGFloat(i)*horizontalHeight, width: size.width, height: size.height) self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity) } } } else { var size = self.image.size size.width *= self.scale size.height *= self.scale let radian: CGFloat = self.rotation * (Double.pi / 180.0) let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian) var imageRect = NSMakeRect(0, 0, size.width, size.height).applying(t) if (self.verticalMode == 0) { imageRect.origin.y = imageSize.height-imageRect.size.height } else if (self.verticalMode == 1) { imageRect.origin.y = (imageSize.height-imageRect.size.height) * 0.5 } else { imageRect.origin.y = 0 } if (self.horizontalMode == 0) { imageRect.origin.x = 0 } else if (self.horizontalMode == 1) { imageRect.origin.x = (imageSize.width-imageRect.size.width) * 0.5 } else { imageRect.origin.x = imageSize.width-imageRect.size.width } let contextCenter = CGPoint(x: rect.midX, y: rect.midY) context.translateBy(x: contextCenter.x, y: contextCenter.y) context.rotate(by: radian) context.translateBy(x: -contextCenter.x, y: -contextCenter.y) let finalRect = NSMakeRect(imageRect.origin.x+(imageRect.size.width-size.width)/2.0, imageRect.origin.y+(imageRect.size.height-size.height)/2.0, size.width, size.height) self.image.draw(in: finalRect, from: NSZeroRect, operation: .overlay, fraction: self.opacity) } } NSGraphicsContext.restoreGraphicsState() NSGraphicsContext.current?.imageInterpolation = .default image.unlockFocus() return image } class func drawImageAtpageRect(rect: NSRect, data: KMWatermarkModel) -> NSImage? { var size = NSZeroSize let text: String = data.text if let image = data.image { size = image.size size.width *= data.scale size.height *= data.scale }else if text.count > 0 { var font = NSFont.systemFont(ofSize: 52) if data.isTilePage { font = NSFont.systemFont(ofSize: data.getTextFontSize()) } let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byCharWrapping let attributes: [NSAttributedString.Key: Any] = [ .paragraphStyle: style, .font: font ] size = text.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: attributes).size } let radian = data.rotation * (CGFloat.pi/180) let t = CGAffineTransform(rotationAngle: radian) var newRect = rect if !data.isTilePage { newRect = CGRect(x: 0, y: 0, width: size.width + 40, height: size.height + 40).applying(t) } let image = NSImage(size: newRect.size) image.lockFocus() NSGraphicsContext.current?.imageInterpolation = .high NSGraphicsContext.saveGraphicsState() NSColor.clear.set() rect.fill() NSGraphicsContext.restoreGraphicsState() guard let context = NSGraphicsContext.current?.cgContext else { return nil } let imageSize = newRect.size NSGraphicsContext.current = NSGraphicsContext(cgContext: context, flipped: false) NSGraphicsContext.saveGraphicsState() if let image = data.image { var size = image.size size.width *= data.scale size.height *= data.scale let width = sqrt(image.size.height * image.size.height + image.size.width * image.size.width) let newRect = CGRect(x: -(width - image.size.width)/2, y: -(width - image.size.height)/2, width: width, height: width) let new_w = newRect.size.width let new_h = newRect.size.height let radian = data.rotation * (CGFloat.pi / 180) let t = CGAffineTransform(rotationAngle: radian) if data.isTilePage { context.translateBy(x: image.size.width/2, y: image.size.height/2) context.concatenate(t) context.translateBy(x: -(image.size.width/2), y: -(image.size.height/2)) let verticalWidth = size.width + data.tileHorizontalSpace * data.scale let horizontalHeight = size.height + data.tileVerticalSpace * data.scale let line: Int = Int((new_h - data.tileVerticalSpace * data.scale)/horizontalHeight + 1) let row: Int = Int((new_w - data.tileHorizontalSpace * data.scale) / verticalWidth + 1) let point = CGPoint(x: image.size.width/2 - size.width/2 + data.horizontalSpace*data.scale, y:image.size.height/2 - size.height/2 + data.verticalSpace * data.scale) for i in 0.. 0 { var font = NSFont.systemFont(ofSize: 52) if data.isTilePage { font = NSFont.systemFont(ofSize: data.getTextFontSize()) } var color = data.getTextColor() var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0 // color.usingColorSpace(NSColorSpace.rg)?.getRed(&red, green: &green, blue: &blue, alpha: nil) color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil) color = NSColor.init(calibratedRed: red, green: green, blue: blue, alpha: data.opacity) size = .zero let alpha = data.opacity let tileHorizontalSpace = data.tileHorizontalSpace let tileVerticalSpace = data.tileVerticalSpace let horizontalSpace = data.horizontalSpace let verticalSpace = data.verticalSpace let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byCharWrapping let attributes: [NSAttributedString.Key: Any] = [ .paragraphStyle: style, .foregroundColor: NSColor(calibratedRed: red, green: green, blue: blue, alpha: alpha), .font: font ] size = text.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: attributes).size let textRect = CGRect(x: 0, y: 0, width: size.width, height: size.height) if data.isTilePage { let width = sqrt(image.size.height * image.size.height + image.size.width * image.size.width) let newRect = CGRect(x: -(width - image.size.width) / 2, y: -(width - image.size.height) / 2, width: width, height: width) let new_w = newRect.size.width let new_h = newRect.size.height context.translateBy(x: image.size.width / 2, y: image.size.height / 2) context.concatenate(CGAffineTransform(rotationAngle: radian)) context.translateBy(x: -(image.size.width / 2), y: -(image.size.height / 2)) let verticalWidth = size.width + tileHorizontalSpace / 3.0 let horizontalHeight = size.height + tileVerticalSpace / 3.0 let line: Int = Int((new_h - tileHorizontalSpace / 3.0) / horizontalHeight + 1) let row: Int = Int((new_w - tileVerticalSpace / 3.0) / verticalWidth + 1) let point = CGPoint(x: image.size.width / 2 - size.width / 2 + horizontalSpace / 3.0, y: image.size.height / 2 - size.height / 2 + verticalSpace / 3.0) for i in 0..