• Swift页面添加水印


    本文主要讨论的是给图片或者视图添加全屏水印。比较常见的是添加单个水印,这个比较好处理,网络上也有很多参考的方法。本文实现的是铺满的全屏水印,具体参考效果如下:

    实现思路:

    1、根据水印文本以及相应样式生成水印图片,水印图大小根据文本计算而来

    2、生成需要铺满水印图片或视图 的空白底图

    3、采用贴地砖的方式将水印图从左至右,从上至下贴在底图上

    具体实现参考代码如下:

    1. /// 创建全铺图片水印
    2. /// - Parameters:
    3. /// - strTxt: 水印文本
    4. /// - fsize: 全铺的尺寸
    5. /// - corners: 圆角信息(可选)
    6. /// - r: 圆角值(可选)
    7. /// - Returns: UIImage
    8. func createWatermarkFor(Text strTxt:String,
    9. andFullSize fsize:CGSize,
    10. andCorners corners:UIRectCorner? = nil,
    11. withRadius r:CGFloat? = nil) -> UIImage {
    12. //[S] 1、设置水印样式
    13. let paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
    14. paragraphStyle.lineBreakMode = .byWordWrapping
    15. paragraphStyle.lineSpacing = 6.0 * Setting.shareInstance.K_APP_PROPORTION
    16. paragraphStyle.alignment = .center
    17. var _attr:[NSAttributedString.Key:Any] = [
    18. .font : UIFont.systemFont(ofSize: 15, weight: .semibold),
    19. .foregroundColor:UIColor.init().colorFromHexInt(hex: 0xE8E8E8, alpha: 0.5),
    20. .paragraphStyle: paragraphStyle,
    21. .kern:1.0,
    22. ]
    23. if #available(iOS 14.0, *) {
    24. _attr[.tracking] = 1.0
    25. }
    26. let attributedString:NSMutableAttributedString = NSMutableAttributedString.init(string: strTxt)
    27. let stringRange = NSMakeRange(0, attributedString.string.utf16.count)
    28. attributedString.addAttributes(_attr,range: stringRange)
    29. //[E]
    30. //[S] 2、建立水印图
    31. let _max_value = attributedString.size().width > attributedString.size().height ? attributedString.size().width : attributedString.size().height
    32. let _size = CGSize.init(width: _max_value + 10, height: _max_value + 10)
    33. //2.1、设置上下文
    34. if UIScreen.main.scale > 1.5 {
    35. UIGraphicsBeginImageContextWithOptions(_size,false,0)
    36. }
    37. else{
    38. UIGraphicsBeginImageContext(_size)
    39. }
    40. var context = UIGraphicsGetCurrentContext()
    41. //2.2、根据中心开启旋转上下文矩阵
    42. //将绘制原点(0,0)调整到源image的中心
    43. context?.concatenate(.init(translationX: _size.width * 0.8, y: _size.height * 0.4))
    44. //以绘制原点为中心旋转45°
    45. context?.concatenate(.init(rotationAngle: -0.25 * .pi))
    46. //将绘制原点恢复初始值,保证context中心点和image中心点处在一个点(当前context已经发生旋转,绘制出的任何layer都是倾斜的)
    47. context?.concatenate(.init(translationX: -_size.width * 0.8, y: -_size.height * 0.4))
    48. //2.3、添加水印文本
    49. attributedString.draw(in: .init(origin: .zero, size: _size))
    50. //2.4、从上下文中获取水印图
    51. let _waterImg = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage.init()
    52. //[E]
    53. //[S] 3、重设上下文,建立底图
    54. if UIScreen.main.scale > 1.5 {
    55. UIGraphicsBeginImageContextWithOptions(fsize,false,0)
    56. }
    57. else{
    58. UIGraphicsBeginImageContext(fsize)
    59. }
    60. context = UIGraphicsGetCurrentContext()
    61. //3.1圆角底图(可选)
    62. if corners != nil && r != nil && r?.isNaN == false && r?.isFinite != false {
    63. let rect:CGRect = .init(origin: .zero, size: fsize)
    64. let bezierPath:UIBezierPath = UIBezierPath.init(roundedRect: rect,
    65. byRoundingCorners: corners!,
    66. cornerRadii: CGSize(width: r!, height: r!))
    67. context?.addPath(bezierPath.cgPath)
    68. }
    69. //3.2 将水印图贴上去
    70. var _tempC = fsize.width / _waterImg.size.width
    71. var _maxColumn:Int = _tempC.isNaN || !_tempC.isFinite ? 1 : Int(_tempC)
    72. if fsize.width.truncatingRemainder(dividingBy: _waterImg.size.width) != 0 {
    73. _maxColumn += 1
    74. }
    75. _tempC = fsize.height / _waterImg.size.height
    76. var _maxRows:Int = _tempC.isNaN || !_tempC.isFinite ? 1 : Int(_tempC)
    77. if fsize.height.truncatingRemainder(dividingBy: _waterImg.size.height) != 0 {
    78. _maxRows += 1
    79. }
    80. for r in 0..<_maxRows {
    81. for c in 0..<_maxColumn {
    82. let _rect:CGRect = .init(origin: .init(x: CGFloat(c) * _waterImg.size.width,
    83. y: CGFloat(r) * _waterImg.size.height),
    84. size: _waterImg.size)
    85. _waterImg.draw(in: _rect)
    86. }
    87. }
    88. //裁剪、透明
    89. context?.clip()
    90. context?.setFillColor(UIColor.clear.cgColor)
    91. context?.fill(.init(origin: .zero, size: fsize))
    92. //3.3 输出最终图形
    93. let _canvasImg = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage.init()
    94. //[E]
    95. //4、关闭图形上下文
    96. UIGraphicsEndImageContext()
    97. return _canvasImg
    98. }


    调用方法示例:

    let _img = createWatermarkFor(Text:"      水印文本1\n 水印文本2\n水印文本3", andFullSize:_imgV.size)


    思考:

    1、水印图需要旋转可参考旋转方向示例图:

     由于旋转的是文本,水印图本身并未旋转,因此可能导致文本会超出水印图的区域而被裁剪,导致未显示全。

    解决方案:

    1、设置水印图的尺寸为水印文本计算而来的宽或高的最大值为其宽度和高度,这样确保旋转后内容不会超出水印(这只是针对水印文本居中对齐的情况)

    2、假如水印文本要求左/右对齐,除了采用方案1,还需要在文本开头添加空白,让其避开可能被裁掉的区域(尤其是一个水印图中要设置多行文本的情况下)

  • 相关阅读:
    WebSocket实现简单聊天功能案例
    中国大陆IP段(含港澳)【2022-08-13】
    程序性能分析
    明日风尚杂志明日风尚杂志社《明日风尚》杂志社2022年第10期目录
    ubuntu下mysql常用命令
    C语言如何做到四舍五入保留小数
    Python模块ADB的, 已经 pyadb
    【源码+文档+调试讲解】微信小程序家政项目小程序
    CVPR2020:Seeing Through Fog Without Seeing Fog
    AIGC|一文揭秘如何利用MYSCALE实现高效图像搜索?
  • 原文地址:https://blog.csdn.net/tianhongfan10106/article/details/132811214