CStampPreview.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. //
  2. // CStampPreview.swift
  3. // ComPDFKit_Tools
  4. //
  5. // Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  8. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  9. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  10. // This notice may not be removed from this file.
  11. //
  12. import UIKit
  13. enum TextStampType: Int {
  14. case center = 0
  15. case left
  16. case right
  17. case none
  18. }
  19. enum TextStampColorType: Int {
  20. case black = 0
  21. case red
  22. case green
  23. case blue
  24. }
  25. class CStampPreview: UIView {
  26. var colors: [Double] = [0.0, 0.0, 0.0]
  27. var textStampStyle: TextStampType = .center
  28. var textStampColorStyle: TextStampColorType = .black {
  29. didSet {
  30. if .red == textStampColorStyle {
  31. colors[0] = 0.57
  32. colors[1] = 0.06
  33. colors[2] = 0.02
  34. } else if .green == textStampColorStyle {
  35. colors[0] = 0.25
  36. colors[1] = 0.42
  37. colors[2] = 0.13
  38. } else if .blue == textStampColorStyle {
  39. colors[0] = 0.09
  40. colors[1] = 0.15
  41. colors[2] = 0.39
  42. } else if .black == textStampColorStyle {
  43. colors[0] = 0
  44. colors[1] = 0
  45. colors[2] = 0
  46. }
  47. }
  48. }
  49. var textStampHaveDate: Bool = false
  50. var textStampHaveTime: Bool = false
  51. var textStampText: String?
  52. var dateTime: String?
  53. var stampBounds: CGRect = .zero
  54. var scale: Float = 0.0
  55. var leftMargin: CGFloat = 0.0
  56. var color: UIColor?
  57. let kStampPreview_OnlyText_Size: CGFloat = 48.0
  58. let kStampPreview_Text_Size: CGFloat = 30.0
  59. let kStampPreview_Date_Size: CGFloat = 20.0
  60. override init(frame: CGRect) {
  61. super.init(frame: frame)
  62. scale = (UIScreen.main.scale == 2.0) ? 2.0 : 1.0
  63. }
  64. required init?(coder: NSCoder) {
  65. fatalError("init(coder:) has not been implemented")
  66. }
  67. func getDateTime() -> String {
  68. let timename = TimeZone.current
  69. let outputFormatter = DateFormatter()
  70. outputFormatter.timeZone = timename
  71. var tDate: String? = nil
  72. if textStampHaveDate && !textStampHaveTime {
  73. outputFormatter.dateFormat = "yyyy/MM/dd"
  74. tDate = outputFormatter.string(from: Date())
  75. } else if textStampHaveTime && !textStampHaveDate {
  76. outputFormatter.dateFormat = "HH:mm:ss"
  77. tDate = outputFormatter.string(from: Date())
  78. } else if textStampHaveDate && textStampHaveTime {
  79. outputFormatter.dateFormat = "yyyy/MM/dd HH:mm"
  80. tDate = outputFormatter.string(from: Date())
  81. }
  82. return tDate ?? ""
  83. }
  84. // Calculate Rect based on text
  85. func fitStampRect() {
  86. var tTextFont: UIFont?
  87. var tTimeFont: UIFont?
  88. var drawText: String?
  89. var dateText: String?
  90. if (textStampText?.count ?? 0 < 1) && (dateTime?.count ?? 0 < 1) {
  91. drawText = "StampText"
  92. tTextFont = UIFont(name: "Helvetica", size: kStampPreview_OnlyText_Size)
  93. } else if (textStampText?.count ?? 0 > 0) && (dateTime?.count ?? 0 > 0) {
  94. tTextFont = UIFont(name: "Helvetica", size: kStampPreview_Text_Size)
  95. tTimeFont = UIFont(name: "Helvetica", size: kStampPreview_Date_Size)
  96. drawText = textStampText
  97. dateText = dateTime
  98. } else {
  99. if ((dateTime?.count ?? 0 > 0)) {
  100. drawText = dateTime
  101. } else {
  102. drawText = textStampText
  103. }
  104. tTextFont = UIFont(name: "Helvetica", size: kStampPreview_OnlyText_Size)
  105. }
  106. let tTextSize = drawText?.size(withAttributes: [.font: tTextFont as Any]) ?? .zero
  107. var tTimeSize = CGSize.zero
  108. if let tTimeFont = tTimeFont {
  109. tTimeSize = dateText?.size(withAttributes: [.font: tTimeFont]) ?? .zero
  110. }
  111. var w = max(tTextSize.width, tTimeSize.width)
  112. var count:CGFloat = 0
  113. if let drawText = drawText {
  114. for i in 0..<drawText.count {
  115. let aStr = String(drawText[drawText.index(drawText.startIndex, offsetBy: i)])
  116. if aStr == " " {
  117. count += 1
  118. }
  119. }
  120. }
  121. if tTextSize.width < tTimeSize.width {
  122. w += 15
  123. } else {
  124. w += 13.0 + 5 * count
  125. }
  126. var h = tTextSize.height + 5
  127. if let _ = dateText {
  128. h = tTextSize.height + tTimeSize.height + 8.011
  129. }
  130. if textStampStyle == .left {
  131. w = CGFloat(Int(Double(w) + Double(h) * 0.618033))
  132. } else if textStampStyle == .right {
  133. w = CGFloat(Int(Double(w) + Double(h) * 0.618033))
  134. }
  135. var x: CGFloat = 0.0
  136. var y: CGFloat = 0.0
  137. scale = 1.0
  138. let maxW: CGFloat = 300 - leftMargin
  139. if CGFloat(w) > maxW {
  140. scale = Float(maxW / CGFloat(w))
  141. h = CGFloat(Int(Double(h) * Double(scale)))
  142. x = frame.size.width / 2.0 - maxW / 2.0
  143. y = frame.size.height / 2.0 - CGFloat(h) / 2.0
  144. stampBounds = CGRect(x: x + leftMargin, y: y, width: maxW, height: h)
  145. } else {
  146. x = frame.size.width / 2.0 - CGFloat(w) / 2.0
  147. y = frame.size.height / 2.0 - CGFloat(h) / 2.0
  148. stampBounds = CGRect(x: x + leftMargin, y: y, width: CGFloat(w), height: h)
  149. }
  150. }
  151. // Only override drawRect: if you perform custom drawing.
  152. // An empty implementation adversely affects performance during animation.
  153. override func draw(_ rect: CGRect) {
  154. dateTime = getDateTime()
  155. fitStampRect()
  156. guard let context = UIGraphicsGetCurrentContext() else {
  157. return
  158. }
  159. context.setFillColor(CPDFColorUtils.CAnnotationSampleDrawBackgoundColor().cgColor)
  160. context.fill(bounds)
  161. if textStampStyle != .none {
  162. drawBounder(context: context)
  163. }
  164. drawText(context)
  165. }
  166. func drawBounder(context: CGContext?) {
  167. guard let context = context else {
  168. return
  169. }
  170. context.saveGState()
  171. var c01 = 1.0, c02 = 1.0, c03 = 1.0, c11 = 1.0, c12 = 1.0, c13 = 1.0
  172. if colors[0] > colors[1] && colors[0] > colors[2] {
  173. c01 = 1.0
  174. c02 = 0.78
  175. c03 = 0.78
  176. c11 = 0.98
  177. c12 = 0.92
  178. c13 = 0.91
  179. } else if colors[1] > colors[0] && colors[1] > colors[2] {
  180. c01 = 0.81
  181. c02 = 0.88
  182. c03 = 0.78
  183. c11 = 0.95
  184. c12 = 0.95
  185. c13 = 0.95
  186. } else if colors[2] > colors[0] && colors[2] > colors[1] {
  187. c01 = 0.79
  188. c02 = 0.81
  189. c03 = 0.89
  190. c11 = 0.90
  191. c12 = 0.95
  192. c13 = 1.0
  193. }
  194. let colorSpace = CGColorSpaceCreateDeviceRGB()
  195. let colors: [CGFloat] = [
  196. c01, c02, c03, 0.9,
  197. c11, c12, c13, 0.9
  198. ]
  199. guard let gradient = CGGradient(colorSpace: colorSpace, colorComponents: colors, locations: nil, count: colors.count/4) else {
  200. return
  201. }
  202. let startPoint = CGPoint(x: stampBounds.origin.x + stampBounds.size.width * 0.75, y: stampBounds.origin.y + stampBounds.size.width * 0.25)
  203. let endPoint = CGPoint(x: stampBounds.origin.x + stampBounds.size.width * 0.25, y: stampBounds.origin.y + stampBounds.size.width * 0.75)
  204. if textStampStyle == TextStampType.center {
  205. drawNormalRect(context: context)
  206. } else if textStampStyle == TextStampType.left {
  207. drawLeftBounder(context)
  208. } else if textStampStyle == TextStampType.right {
  209. drawRightBounder(context)
  210. }
  211. context.clip()
  212. context.saveGState()
  213. if let context = UIGraphicsGetCurrentContext() {
  214. context.saveGState()
  215. context.addRect(stampBounds)
  216. context.clip()
  217. context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
  218. context.restoreGState()
  219. }
  220. if textStampStyle == TextStampType.center {
  221. drawNormalRect(context: context)
  222. } else if textStampStyle == TextStampType.left {
  223. drawLeftBounder(context)
  224. } else if textStampStyle == TextStampType.right {
  225. drawRightBounder(context)
  226. }
  227. context.strokePath()
  228. }
  229. func drawNormalRect(context: CGContext) {
  230. let tmpHeight = 11.0 * stampBounds.size.height/50
  231. let tmpWidth = 3.0 * stampBounds.size.height/50
  232. let hw1 = 5.54492 * stampBounds.size.height/50
  233. let hw2 = 4.40039 * stampBounds.size.height/50
  234. context.beginPath()
  235. context.move(to: CGPoint(x: stampBounds.origin.x+tmpWidth, y: stampBounds.origin.y+stampBounds.size.height-tmpHeight))
  236. context.addCurve(to: CGPoint(x: stampBounds.origin.x+tmpHeight, y: stampBounds.origin.y+stampBounds.size.height-tmpWidth),
  237. control1: CGPoint(x: stampBounds.origin.x+tmpWidth, y: stampBounds.origin.y+stampBounds.size.height-tmpHeight+hw2),
  238. control2: CGPoint(x: stampBounds.origin.x+tmpHeight-hw1, y: stampBounds.origin.y+stampBounds.size.height-tmpWidth))
  239. context.addLine(to: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpHeight, y: stampBounds.origin.y+stampBounds.size.height-tmpWidth))
  240. context.addCurve(to: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpWidth, y: stampBounds.origin.y+stampBounds.size.height-tmpHeight),
  241. control1: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpHeight+hw1, y: stampBounds.origin.y+stampBounds.size.height-tmpWidth),
  242. control2: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpWidth, y: stampBounds.origin.y+stampBounds.size.height-tmpHeight+hw2))
  243. context.addLine(to: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpWidth, y: stampBounds.origin.y+tmpHeight))
  244. context.addCurve(to: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpHeight, y: stampBounds.origin.y+tmpWidth),
  245. control1: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpWidth, y: stampBounds.origin.y+tmpHeight-hw2),
  246. control2: CGPoint(x: stampBounds.origin.x+stampBounds.size.width-tmpHeight+hw1, y: stampBounds.origin.y+tmpWidth))
  247. context.addLine(to: CGPoint(x: stampBounds.origin.x+tmpHeight, y: stampBounds.origin.y+tmpWidth))
  248. context.addCurve(to: CGPoint(x: stampBounds.origin.x+tmpWidth, y: stampBounds.origin.y+tmpHeight),
  249. control1: CGPoint(x: stampBounds.origin.x+tmpHeight-hw1, y: stampBounds.origin.y+tmpWidth),
  250. control2: CGPoint(x: stampBounds.origin.x+tmpWidth, y: stampBounds.origin.y+tmpHeight-hw2))
  251. context.addLine(to: CGPoint(x: stampBounds.origin.x+tmpWidth, y: stampBounds.origin.y+stampBounds.size.height-tmpHeight))
  252. context.closePath()
  253. }
  254. func drawLeftBounder(_ context: CGContext) {
  255. let tmpHeight = 11.0 * stampBounds.size.height/50
  256. let tmpWidth = 3.0 * stampBounds.size.height/50
  257. let hw1 = 5.54492 * stampBounds.size.height/50
  258. let hw2 = 4.40039 * stampBounds.size.height/50
  259. let x0 = stampBounds.origin.x + stampBounds.size.height * 0.618033
  260. let y0 = stampBounds.origin.y
  261. let x1 = stampBounds.origin.x + stampBounds.size.width
  262. let y1 = stampBounds.origin.y + stampBounds.size.height
  263. let xp = stampBounds.origin.x
  264. let yp = stampBounds.origin.y + stampBounds.size.height / 2.0
  265. context.beginPath()
  266. context.move(to: CGPoint(x: x0 + tmpHeight, y: y1 - tmpWidth))
  267. context.addLine(to: CGPoint(x: x1 - tmpHeight, y: y1 - tmpWidth))
  268. context.addCurve(to: CGPoint(x: x1 - tmpWidth, y: y1 - tmpHeight),
  269. control1: CGPoint(x: x1 - tmpHeight + hw1, y: y1 - tmpWidth),
  270. control2: CGPoint(x: x1 - tmpWidth, y: y1 - tmpHeight + hw2))
  271. context.addLine(to: CGPoint(x: x1 - tmpWidth, y: y0 + tmpHeight))
  272. context.addCurve(to: CGPoint(x: x1 - tmpHeight, y: y0 + tmpWidth),
  273. control1: CGPoint(x: x1 - tmpWidth, y: y0 + tmpHeight - hw2),
  274. control2: CGPoint(x: x1 - tmpHeight + hw1, y: y0 + tmpWidth))
  275. context.addLine(to: CGPoint(x: x0 + tmpHeight, y: y0 + tmpWidth))
  276. context.addLine(to: CGPoint(x: xp + tmpHeight, y: yp))
  277. context.addLine(to: CGPoint(x: x0 + tmpHeight, y: y1 - tmpWidth))
  278. context.closePath()
  279. }
  280. func drawRightBounder(_ context: CGContext) {
  281. let tmpHeight = 11.0 * stampBounds.size.height/50
  282. let tmpWidth = 3.0 * stampBounds.size.height/50
  283. let hw1 = 5.54492 * stampBounds.size.height/50
  284. let hw2 = 4.40039 * stampBounds.size.height/50
  285. let x0 = stampBounds.origin.x
  286. let y0 = stampBounds.origin.y
  287. let x1 = stampBounds.origin.x + stampBounds.size.width - stampBounds.size.height * 0.618033
  288. let y1 = stampBounds.origin.y + stampBounds.size.height
  289. let xp = stampBounds.origin.x + stampBounds.size.width
  290. let yp = stampBounds.origin.y + stampBounds.size.height / 2.0
  291. context.beginPath()
  292. context.move(to: CGPoint(x: x0 + tmpWidth, y: y1 - tmpHeight))
  293. context.addCurve(to: CGPoint(x: x0 + tmpHeight, y: y1 - tmpWidth),
  294. control1: CGPoint(x: x0 + tmpWidth, y: y1 - tmpHeight + hw2),
  295. control2: CGPoint(x: x0 + tmpHeight - hw1, y: y1 - tmpWidth))
  296. context.addLine(to: CGPoint(x: x1 - tmpHeight, y: y1 - tmpWidth))
  297. context.addLine(to: CGPoint(x: xp - tmpHeight, y: yp))
  298. context.addLine(to: CGPoint(x: x1 - tmpHeight, y: y0 + tmpWidth))
  299. context.addLine(to: CGPoint(x: x0 + tmpHeight, y: y0 + tmpWidth))
  300. context.addCurve(to: CGPoint(x: x0 + tmpWidth, y: y0 + tmpHeight),
  301. control1: CGPoint(x: x0 + tmpHeight - hw1, y: y0 + tmpWidth),
  302. control2: CGPoint(x: x0 + tmpWidth, y: y0 + tmpHeight - hw2))
  303. context.addLine(to: CGPoint(x: x0 + tmpWidth, y: y1 - tmpHeight))
  304. context.closePath()
  305. }
  306. func drawText(_ context: CGContext?) {
  307. guard let context = context else {
  308. return
  309. }
  310. context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
  311. var drawText: String?
  312. var dateText: String?
  313. if (textStampText?.count ?? 0 < 1) && (dateTime?.count ?? 0 < 1) {
  314. drawText = "StampText"
  315. } else if (textStampText?.count ?? 0 > 0) && (dateTime?.count ?? 0 > 0) {
  316. drawText = textStampText
  317. dateText = dateTime
  318. }else {
  319. if((dateTime?.count ?? 0 > 0)) {
  320. drawText = dateTime
  321. } else {
  322. drawText = textStampText
  323. }
  324. }
  325. if (dateText?.count ?? 0 < 1) {
  326. let fontsize = Float(kStampPreview_OnlyText_Size) * scale
  327. let font = UIFont(name: "Helvetica", size: CGFloat(fontsize))
  328. var rt = stampBounds.insetBy(dx: 0, dy: 0)
  329. rt.origin.x += CGFloat(8.093 * scale)
  330. if textStampStyle == .left {
  331. rt.origin.x += rt.size.height * 0.618033
  332. }
  333. UIGraphicsPushContext(context)
  334. let attributes: [NSAttributedString.Key: Any] = [
  335. .font: font as Any,
  336. .paragraphStyle: NSParagraphStyle.default,
  337. .foregroundColor: UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1)
  338. ]
  339. drawText?.draw(in: rt, withAttributes: attributes)
  340. UIGraphicsPopContext()
  341. } else {
  342. var tFontSize = Float(kStampPreview_Text_Size) * Float(scale)
  343. var tFont = UIFont(name: "Helvetica", size: CGFloat(tFontSize))
  344. var tTextRT = stampBounds.insetBy(dx: 0, dy: 0)
  345. tTextRT.origin.x += CGFloat(8.093 * scale)
  346. if textStampStyle == .left {
  347. tTextRT.origin.x += tTextRT.size.height * 0.618033
  348. }
  349. UIGraphicsPushContext(context)
  350. UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1).set()
  351. if !(drawText?.isEmpty == true) {
  352. let attributes: [NSAttributedString.Key: Any] = [
  353. .font: tFont as Any,
  354. .paragraphStyle: NSParagraphStyle.default,
  355. .foregroundColor: UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1)
  356. ]
  357. drawText?.draw(in: tTextRT, withAttributes: attributes)
  358. var tDateRT = stampBounds.insetBy(dx: 0, dy: 0)
  359. tDateRT.origin.x += CGFloat(8.093 * Float(scale))
  360. if textStampStyle == .left {
  361. tDateRT.origin.x += tDateRT.size.height * 0.618033
  362. }
  363. tDateRT.origin.y = tDateRT.origin.y + CGFloat(tFontSize) + CGFloat(6.103 * scale)
  364. tFontSize = Float(kStampPreview_Date_Size) * Float(scale)
  365. tFont = UIFont(name: "Helvetica", size: CGFloat(tFontSize))
  366. let attributess: [NSAttributedString.Key: Any] = [
  367. .font: tFont as Any,
  368. .paragraphStyle: NSParagraphStyle.default,
  369. .foregroundColor: UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1)
  370. ]
  371. dateText?.draw(in: tDateRT, withAttributes: attributess)
  372. } else {
  373. let fontsize = Float(kStampPreview_Date_Size) * Float(scale)
  374. let font = UIFont(name: "Helvetica", size: CGFloat(tFontSize))
  375. var rt = stampBounds.insetBy(dx: 0, dy: 0)
  376. rt.origin.x += CGFloat(8.093 * scale)
  377. if textStampStyle == .left {
  378. rt.origin.x += rt.size.height * 0.618033
  379. }
  380. let attributes: [NSAttributedString.Key: Any] = [
  381. .font: font as Any,
  382. .paragraphStyle: NSParagraphStyle.default,
  383. .foregroundColor: UIColor(red: colors[0], green: colors[1], blue: colors[2], alpha: 1)
  384. ]
  385. dateText?.draw(in: rt, withAttributes: attributes)
  386. }
  387. UIGraphicsPopContext()
  388. }
  389. }
  390. func renderImage() -> UIImage? {
  391. // Implementation for rendering an image
  392. let image = renderImageFromView(self)
  393. return image
  394. }
  395. /* Convert UIView to UIImage */
  396. func renderImageFromView(_ view: UIView) -> UIImage? {
  397. UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 1.0)
  398. guard let context = UIGraphicsGetCurrentContext() else { return nil }
  399. context.translateBy(x: 1.0, y: 1.0)
  400. view.layer.render(in: context)
  401. let image = UIGraphicsGetImageFromCurrentImageContext()
  402. UIGraphicsEndImageContext()
  403. return image
  404. }
  405. }