本文主要讨论的是给图片或者视图添加全屏水印。比较常见的是添加单个水印,这个比较好处理,网络上也有很多参考的方法。本文实现的是铺满的全屏水印,具体参考效果如下:
实现思路:
1、根据水印文本以及相应样式生成水印图片,水印图大小根据文本计算而来
2、生成需要铺满水印图片或视图 的空白底图
3、采用贴地砖的方式将水印图从左至右,从上至下贴在底图上
具体实现参考代码如下:
- /// 创建全铺图片水印
- /// - Parameters:
- /// - strTxt: 水印文本
- /// - fsize: 全铺的尺寸
- /// - corners: 圆角信息(可选)
- /// - r: 圆角值(可选)
- /// - Returns: UIImage
- func createWatermarkFor(Text strTxt:String,
- andFullSize fsize:CGSize,
- andCorners corners:UIRectCorner? = nil,
- withRadius r:CGFloat? = nil) -> UIImage {
-
- //[S] 1、设置水印样式
- let paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
- paragraphStyle.lineBreakMode = .byWordWrapping
- paragraphStyle.lineSpacing = 6.0 * Setting.shareInstance.K_APP_PROPORTION
- paragraphStyle.alignment = .center
-
- var _attr:[NSAttributedString.Key:Any] = [
- .font : UIFont.systemFont(ofSize: 15, weight: .semibold),
- .foregroundColor:UIColor.init().colorFromHexInt(hex: 0xE8E8E8, alpha: 0.5),
- .paragraphStyle: paragraphStyle,
- .kern:1.0,
- ]
-
- if #available(iOS 14.0, *) {
- _attr[.tracking] = 1.0
- }
-
- let attributedString:NSMutableAttributedString = NSMutableAttributedString.init(string: strTxt)
- let stringRange = NSMakeRange(0, attributedString.string.utf16.count)
- attributedString.addAttributes(_attr,range: stringRange)
- //[E]
-
- //[S] 2、建立水印图
- let _max_value = attributedString.size().width > attributedString.size().height ? attributedString.size().width : attributedString.size().height
- let _size = CGSize.init(width: _max_value + 10, height: _max_value + 10)
-
- //2.1、设置上下文
- if UIScreen.main.scale > 1.5 {
- UIGraphicsBeginImageContextWithOptions(_size,false,0)
- }
- else{
- UIGraphicsBeginImageContext(_size)
- }
- var context = UIGraphicsGetCurrentContext()
-
- //2.2、根据中心开启旋转上下文矩阵
- //将绘制原点(0,0)调整到源image的中心
- context?.concatenate(.init(translationX: _size.width * 0.8, y: _size.height * 0.4))
-
- //以绘制原点为中心旋转45°
- context?.concatenate(.init(rotationAngle: -0.25 * .pi))
-
- //将绘制原点恢复初始值,保证context中心点和image中心点处在一个点(当前context已经发生旋转,绘制出的任何layer都是倾斜的)
- context?.concatenate(.init(translationX: -_size.width * 0.8, y: -_size.height * 0.4))
-
- //2.3、添加水印文本
- attributedString.draw(in: .init(origin: .zero, size: _size))
-
- //2.4、从上下文中获取水印图
- let _waterImg = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage.init()
- //[E]
-
- //[S] 3、重设上下文,建立底图
- if UIScreen.main.scale > 1.5 {
- UIGraphicsBeginImageContextWithOptions(fsize,false,0)
- }
- else{
- UIGraphicsBeginImageContext(fsize)
- }
- context = UIGraphicsGetCurrentContext()
-
- //3.1圆角底图(可选)
- if corners != nil && r != nil && r?.isNaN == false && r?.isFinite != false {
- let rect:CGRect = .init(origin: .zero, size: fsize)
- let bezierPath:UIBezierPath = UIBezierPath.init(roundedRect: rect,
- byRoundingCorners: corners!,
- cornerRadii: CGSize(width: r!, height: r!))
-
- context?.addPath(bezierPath.cgPath)
- }
-
- //3.2 将水印图贴上去
- var _tempC = fsize.width / _waterImg.size.width
- var _maxColumn:Int = _tempC.isNaN || !_tempC.isFinite ? 1 : Int(_tempC)
- if fsize.width.truncatingRemainder(dividingBy: _waterImg.size.width) != 0 {
- _maxColumn += 1
- }
-
- _tempC = fsize.height / _waterImg.size.height
- var _maxRows:Int = _tempC.isNaN || !_tempC.isFinite ? 1 : Int(_tempC)
- if fsize.height.truncatingRemainder(dividingBy: _waterImg.size.height) != 0 {
- _maxRows += 1
- }
-
- for r in 0..<_maxRows {
- for c in 0..<_maxColumn {
- let _rect:CGRect = .init(origin: .init(x: CGFloat(c) * _waterImg.size.width,
- y: CGFloat(r) * _waterImg.size.height),
- size: _waterImg.size)
- _waterImg.draw(in: _rect)
- }
- }
-
- //裁剪、透明
- context?.clip()
- context?.setFillColor(UIColor.clear.cgColor)
- context?.fill(.init(origin: .zero, size: fsize))
-
- //3.3 输出最终图形
- let _canvasImg = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage.init()
- //[E]
-
- //4、关闭图形上下文
- UIGraphicsEndImageContext()
-
- return _canvasImg
-
- }
调用方法示例:
let _img = createWatermarkFor(Text:" 水印文本1\n 水印文本2\n水印文本3", andFullSize:_imgV.size)
思考:
1、水印图需要旋转可参考旋转方向示例图:
由于旋转的是文本,水印图本身并未旋转,因此可能导致文本会超出水印图的区域而被裁剪,导致未显示全。
解决方案:
1、设置水印图的尺寸为水印文本计算而来的宽或高的最大值为其宽度和高度,这样确保旋转后内容不会超出水印(这只是针对水印文本居中对齐的情况)
2、假如水印文本要求左/右对齐,除了采用方案1,还需要在文本开头添加空白,让其避开可能被裁掉的区域(尤其是一个水印图中要设置多行文本的情况下)