DDGScreenShot--iOS 各種截圖,webView wkWebView 生成長圖,加logo,打標籤

東閣堂主發表於2018-03-28

寫在前面

最近有這麼一個需求,分享頁面,分享的是web訂單截圖,既然是web 就會有超出螢幕的部分,
生成的圖片還要加上我們的二維碼,這就涉及到圖片的合成了。
有了這樣的需求,就是各種google.也算解決了自己的需求,另外,也總結了一下,對需求做了下擴充,目前是swift4.0版本。
複製程式碼

整合成一個三方庫,以下只是部分程式碼,詳細程式碼及demo請見,github地址https://github.com/dudongge/DDGScreenShot

DDGScreenShot 所有功能演示

image
image


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, width: (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, width: 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, width: 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, width: 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()
            }
        }
    }
複製程式碼

兩張圖片合為一張(一張底圖,一張logo)

在UIImage上做了擴充
let imageRef = self.cgImage
        let w: CGFloat = CGFloat((imageRef?.width)!)
        let h: CGFloat = CGFloat((imageRef?.height)!)
        //以1.png的圖大小為畫布建立上下文
        UIGraphicsBeginImageContext(CGSize(width: w, height: h))
        self.draw(in: CGRect(x: 0, y: 0, width: w, height: h))
        //先把1.png 畫到上下文中
        logo.draw(in: CGRect(x: logoOrigin.x,
                             y: logoOrigin.y,
                             width: 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, width: 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, width: 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'
        ```

複製程式碼

相關文章