zoukankan      html  css  js  c++  java
  • DDGScreenShot — 复杂屏幕截屏(如view ScrollView webView wkwebView)

    写在前面

    最近有这么一个需求,分享页面,分享的是web订单截图,既然是web 就会有超出屏幕的部分,
    生成的图片还要加上我们的二维码,这就涉及到图片的合成了。
    有了这样的需求,就是各种google.也算解决了自己的需求,另外,也总结了一下,对需求做了下拓展,目前是swift4.0版本。
    

    整合成一个三方库,以下只是部分代码,详细代码及demo请见,github地址https://github.com/dudongge/DDGScreenShot


    View生成图片

    代码也比较简单 screenShotImage 就是截取后的图片
            let context = UIGraphicsGetCurrentContext()
            context?.saveGState()
            context?.translateBy(x: -self.frame.origin.x, y: -self.frame.origin.y);
             self.layer.render(in: context!)
            let screenShotImage = UIGraphicsGetImageFromCurrentImageContext()
            context?.restoreGState();
            UIGraphicsEndImageContext()
    

    ScrollView生成图片

    只要实现原理是计算偏移量,每一屏绘制一次,放在内存里,最后将所有的图片组合成一张图片 screenShotImage就是最终图片
    public func DDGContentScrollScreenShot (_ completionHandler: @escaping (_ screenShotImage: UIImage?) -> Void) {
            
            self.isShoting = true
            
            let snapShotView = self.snapshotView(afterScreenUpdates: true)
            snapShotView?.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y,  (snapShotView?.frame.size.width)!, height: (snapShotView?.frame.size.height)!)
            self.superview?.addSubview(snapShotView!)
    
            let bakOffset    = self.contentOffset
            
            let page  = floorf(Float(self.contentSize.height / self.bounds.height))
            
            UIGraphicsBeginImageContextWithOptions(self.contentSize, false, UIScreen.main.scale)
            
            self.DDGContentScrollPageDraw(0, maxIndex: Int(page), drawCallback: { [weak self] () -> Void in
                let strongSelf = self
                
                let screenShotImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                
                strongSelf?.setContentOffset(bakOffset, animated: false)
                snapShotView?.removeFromSuperview()
                
                strongSelf?.isShoting = false
                
                completionHandler(screenShotImage)
            })
            
        }
        
        fileprivate func DDGContentScrollPageDraw (_ index: Int, maxIndex: Int, drawCallback: @escaping () -> Void) {
            
            self.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.frame.size.height), animated: false)
            let splitFrame = CGRect(x: 0, y: CGFloat(index) * self.frame.size.height,  bounds.size.width, height: bounds.size.height)
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
                self.drawHierarchy(in: splitFrame, afterScreenUpdates: true)
                
                if index < maxIndex {
                    self.DDGContentScrollPageDraw(index + 1, maxIndex: maxIndex, drawCallback: drawCallback)
                }else{
                    drawCallback()
                }
            }
        }
    

    UIwebView生成图片 && wkwebView

    绘制时大同小异,只是wkwebView 调用的绘制方法为:drawHierarchy 其核心代码如下
    采用递归,直到拿到最后一个偏移量。
    fileprivate func DDGRenderImageView(_ completionHandler: @escaping (_ screenShotImage: UIImage?) -> Void) {
            let ddgTempRenderView = UIView(frame: CGRect(x: 0, y: 0,  self.contentSize.width, height: self.contentSize.height))
            self.removeFromSuperview()
            ddgTempRenderView.addSubview(self)
            
            self.contentOffset = CGPoint.zero
            self.frame         = ddgTempRenderView.bounds
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
                let bounds = self.bounds
                UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
                
                if (self.DDGContainsWKWebView()) {
                    self.drawHierarchy(in: bounds, afterScreenUpdates: true)
                }else{
                    self.layer.render(in: UIGraphicsGetCurrentContext()!)
                }
                let screenShotImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                
                completionHandler(screenShotImage)
            }
        }
    fileprivate func shotScreenContentScrollPageDraw (_ index: Int, maxIndex: Int, drawCallback: @escaping () -> Void) {
            
            self.scrollView.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.scrollView.frame.size.height), animated: false)
            let splitFrame = CGRect(x: 0, y: CGFloat(index) * self.scrollView.frame.size.height,  bounds.size.width, height: bounds.size.height)
            
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
                self.drawHierarchy(in: splitFrame, afterScreenUpdates: true)
                
                if index < maxIndex {
                    self.shotScreenContentScrollPageDraw(index + 1, maxIndex: maxIndex, drawCallback: drawCallback)
                }else{
                    drawCallback()
                }
            }
        }
    

    在UIImage上做了拓展
    let imageRef = self.cgImage
            let w: CGFloat = CGFloat((imageRef?.width)!)
            let h: CGFloat = CGFloat((imageRef?.height)!)
            //以1.png的图大小为画布创建上下文
            UIGraphicsBeginImageContext(CGSize( w, height: h))
            self.draw(in: CGRect(x: 0, y: 0,  w, height: h))
            //先把1.png 画到上下文中
            logo.draw(in: CGRect(x: logoOrigin.x,
                                 y: logoOrigin.y,
                                  logoSize.width,
                                 height:logoSize.height))
            //再把小图放在上下文中
            let resultImg: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
            //从当前上下文中获得最终图片
            UIGraphicsEndImageContext()
            return resultImg!
    
    

    在图片上写文字/加标签

    同样对UIimage 做了拓展,增加了几个参数
      public func drawTextInImage(text: String,
                             textColor: UIColor,
                             textFont: CGFloat,
                             textBgColor: UIColor,
                             textX: CGFloat,
                             textY: CGFloat )->UIImage {
            //开启图片上下文
            UIGraphicsBeginImageContext(self.size)
            //图形重绘
            self.draw(in: CGRect.init(x: 0, y: 0,  self.size.width, height: self.size.height))
            //水印文字属性
            let att = [NSAttributedStringKey.foregroundColor: textColor,
                       NSAttributedStringKey.font: UIFont.systemFont(ofSize: textFont),
                       NSAttributedStringKey.backgroundColor: textBgColor]
            //水印文字大小
            let text = NSString(string: text)
            let size =  text.size(withAttributes: att)
            //绘制文字
            text.draw(in: CGRect.init(x: textX, y: textY,  size.width, height: size.height), withAttributes: att)
            //从当前上下文获取图片
            let image = UIGraphicsGetImageFromCurrentImageContext()
            //关闭上下文
            UIGraphicsEndImageContext()
            return image!
        }
    

    结束语

    空间有限,所注代码不全,我把上述功能整理成了最新的带三方库,
    以后会加上图片的相关处理,比如美颜,剪切,马赛克,组图等,
    附上我的git地址:https://github.com/dudongge/DDGScreenShot
    有什么问题也可以联系我QQ:532835032
    如果对您有帮助,请您不吝star一下,增加我更新的动力
    

    附上github上READER.ME文件部分内容

    ## view截屏:
        view.DDGScreenShot { (image) in
             拿到 image 
             各种复杂装逼操作
             、、、、
        }
       ## ScrollView截屏:
        scrollView.DDGContentScrollScreenShot { (image) in
             拿到 image 
             各种复杂装逼操作
             、、、、
        }
      ## webView截屏:
        webView.DDGContentscreenShot { (image) in
             拿到 image 
             各种复杂装逼操作
             、、、、
        }
      ## wkwebView截屏: 方法和webView 一样,内部做了校验
          webView.DDGContentscreenShot { (image) in
               拿到 image 
               各种复杂装逼操作
               、、、、
          }
      ## image 加 logo
         let image = image.composeImageWithLogo( logo: UIImage,
                                   logoOrigin: CGPoint,
                                   logoSize:CGSize) 
         传入 logo图片,logo位置 logo 大小 就可以得到一张生成好的图片                         
             、、、、
      ## image 加 标签,水印,文字
         let image = image.drawTextInImage(text: String,
                             textColor: UIColor,
                             textFont: CGFloat,
                             textBgColor: UIColor,
                             textX: CGFloat,
                             textY: CGFloat ) 
         传入 文字、文字颜色、字体大小、背景颜色,字体起始位置 就可以得到一张生成好的带标签的图片                         
             、、、、
             注,此方法在提交pod有问题,故将方法屏蔽,有需要的可以拷贝代码,到本地
    
    ## 使用pod
         iOS 9.0+, Swift 4.0+(Compatiable)
            使用pod 导入
            pod 'DDGScreenShot', '~> 1.0.1'
            ```
    
    

    欢迎查看DDGScreenShot

    其余功能如下

    1. (一)DDGScreenShot — 复杂屏幕截屏(如view ScrollView webView wkwebView)
    2. (二)DDGScreenShot--iOS 图片处理--多图片拼接
    3. (三)DDGScreenShot--iOS 图片裁剪,切圆角,加边框,你还用cornerRadius,还有更高级的用法
    4. (四)DDGScreenShot—图片擦除功能
    5. (五)DDGScreenShot—截取图片的任意部分
    6. (六)DDGScreenShot —图片加各种滤镜高逼格操作
    7. (七)DDGScreenShot —图片加高斯模糊,老电影效果
  • 相关阅读:
    功能类控件
    关系类控件-明细表
    WPF MenuItem 四种角色分析
    自定义的 ListBoxItem 自适应ListBox的宽度
    由DataGridTextColumn不能获取到父级DataContext引发的思考
    GDI+中发生一般性错误的解决办法(转帖)
    WPF中RadioButton绑定数据的正确方法
    C# 使用XML序列化对象(二)
    C# 使用XML序列化对象(一)
    WPF中RadioButton的分组
  • 原文地址:https://www.cnblogs.com/dudongge/p/9013613.html
Copyright © 2011-2022 走看看