programing

UI View를 이미지로 변환하는 방법

fastcode 2023. 4. 10. 22:17
반응형

UI View를 이미지로 변환하는 방법

UIView를 이미지로 변환하여 앱에 저장하고 싶습니다.뷰의 스크린샷을 찍거나 이미지로 변환하는 방법과 앱에 저장하는 방법(카메라 롤이 아님)을 가르쳐 주세요.뷰 코드는 다음과 같습니다.

var overView   = UIView(frame: CGRectMake(0, 0, self.view.frame.width/1.3, self.view.frame.height/1.3))
overView.center = CGPointMake(CGRectGetMidX(self.view.bounds),
CGRectGetMidY(self.view.bounds)-self.view.frame.height/16);
overView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(overView)
self.view.bringSubviewToFront(overView)

UIView효과가 있을 거야

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

애플은 사용을 권장하지 않는다UIGraphicsBeginImageContextP3 - iOS 10 - OS 10 - P3 p p p p 。 UIGraphicsBeginImageContextRGB 및 32 트 。은 새로운 .UIGraphicsImageRenderer완전한 컬러 관리, 블록 기반, PDF 및 이미지 서브클래스가 있으며 컨텍스트 수명을 자동으로 관리하는 API입니다.상세한 것에 대하여는, WWDC16 세션 205 를 참조해 주세요(이미지 렌더링은 11시 50분경부터 시작됩니다).

하려면 , 「」를 사용합니다.#available이전 버전의 iOS로 폴백합니다.

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContext(self.frame.size)
            self.layer.render(in:UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImage(cgImage: image!.cgImage!)
        }
    }
}

내선번호를 사용할 수 있습니다.

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

drawViewHierarchyInRect:afterScreenUpdates:renderInContext보다 몇 배 고속으로 UIView를 이미지로 변환합니다.

중요사항: viewDidLoad 또는 viewWillAppear에서 이 함수를 호출하지 마십시오. 뷰가 완전히 표시/로드된 후 캡처를 해야 합니다.

Obj C

     UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f);
     [myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO];
     UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     myImageView.image =  snapshotImageFromMyView;

편집한 이미지 저장 사진 앨범

     UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);

스위프트 3/4

    UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.isOpaque, 0.0)
    myView.drawHierarchy(in: myView.bounds, afterScreenUpdates: false)
    let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    print(snapshotImageFromMyView)
    myImageView.image = snapshotImageFromMyView

확장자, iOS11, swift3/4로 매우 쉽게 일반화할 수 있습니다.

extension UIImage{
    convenience init(view: UIView) {

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    self.init(cgImage: (image?.cgImage)!)

  }
}


Use : 
 //myView is completly loaded/visible , calling this code after only after viewDidAppear is call
 imgVV.image = UIImage.init(view: myView)
 // Simple image object
 let img =  UIImage.init(view: myView)

iOS 10의 경우:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)
    }
}

iOS 10 및 Swift 3의 베스트 프랙티스

iOS 9 및 그 이전 버전을 지원하면서 iOS 13, Xcode 11.1, Swift 5.1에서도 동작합니다.

extension UIView {

    func asImage() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
            defer { UIGraphicsEndImageContext() }
            guard let currentContext = UIGraphicsGetCurrentContext() else {
                return nil
            }
            self.layer.render(in: currentContext)
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
}

질문의 의미를 잘 모르겠습니다.

(카메라 롤이 아닌) 앱에 저장하는 가장 좋은 방법은 무엇입니까?

    UIGraphicsBeginImageContext(self.view.bounds.size);        
    self.view.layer.renderInContext(UIGraphicsGetCurrentContext())
    var screenShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

예를 들어 크기가 50인 경우 100,100에 50입니다.다음을 사용하여 스크린샷을 찍을 수 있습니다.

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0);
    self.view.drawViewHierarchyInRect(CGRectMake(-50,-5-,view.bounds.size.width,view.bounds.size.height), afterScreenUpdates: true)
    var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();

내 생각에 이니셜라이저에 대한 접근 방식은 두 가지 이미지를 생성하기 때문에 그다지 좋지 않다.

나는 이것을 선호한다:

extension UIView {
    var snapshot: UIImage? {
        UIGraphicsBeginImageContext(self.frame.size)
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Swift 4.2, iOS 10

extension UIView {

    // If Swift version is lower than 4.2, 
    // You should change the name. (ex. var renderedImage: UIImage?)

    var image: UIImage? {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) }
    }
}

샘플

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = .blue

let view2 = UIView(frame: CGRect(x: 10, y: 10, width: 20, height: 20))
view2.backgroundColor = .red
view.addSubview(view2)

let imageView = UIImageView(image: view.image)

여기에 이미지 설명 입력

Xcode 9/Swift 3.2/Swift 4 및 Xcode 8/Swift 3에서 사용할 수 있습니다.

 if #available(iOS 10.0, *) {

     // for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson's code
     let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
     let capturedImage = renderer.image { 
         (ctx) in
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
     }
     return capturedImage

 } else {

     // for Xcode 8/Swift 3
     UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
     view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
     let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
     UIGraphicsEndImageContext()
     return capturedImage!
 }

함수 내에서 사용하는 방법은 다음과 같습니다.

fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage {

     guard (view != nil) else{

        // if the view is nil (it's happened to me) return an alternative image
        let errorImage = UIImage(named: "Error Image")
        return errorImage
     }

     // if the view is all good then convert the image inside the view to a uiimage
     if #available(iOS 10.0, *) {

         let renderer = UIGraphicsImageRenderer(size: view!.bounds.size)
         let capturedImage = renderer.image { 
             (ctx) in
             view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true)
         }
         return capturedImage

     } else {

         UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0)
         view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false)
         let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()
         return capturedImage!
     }
}

함수에서 반환된 이미지를 사용하여 작업을 수행하는 방법은 다음과 같습니다.

@IBOutlet weak fileprivate var myCustomView: UIView!
var myPic: UIImage?

let myImageView = UIImageView()

@IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) {

   myPic = captureUIImageFromUIView(myCustomView)

   // display the pic inside a UIImageView
   myImageView.image = myPic!
}

허드슨으로부터 Xcode 9/Swift 3.2/Swift 4의 답변을 받았습니다.uiview를 uiimage로 변환합니다.

Xcode 8/Swift 3은 오래전에 SOGG의 어딘가에서 입수했는데, 어디에 있는지 잊어버렸습니다.

var snapshot = overView.snapshotViewAfterScreenUpdates(false)

또는 목적(c)으로

UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];

이렇게 확장자를 사용하면 쉽게 사용할 수 있습니다.

// Take a snapshot from a view (just one view)
let viewSnapshot = myView.snapshot

// Take a screenshot (with every views in screen)
let screenSnapshot = UIApplication.shared.snapshot

// Take a snapshot from UIImage initialization
UIImage(view: self.view)

이러한 확장 메서드/변수를 사용하려면 다음을 구현하십시오.

  1. UIMage 확장

    extension UIImage {
        convenience init(view: UIView) {
            if let cgImage = view.snapshot?.cgImage {
                self.init(cgImage: cgImage)
            } else {
                self.init()
            }
        }
    }
    
  2. UIView 확장

    extension UIView {
    
        var snapshot: UIImage? {
            UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0)
            if UIGraphicsGetCurrentContext() != nil {
                drawHierarchy(in: bounds, afterScreenUpdates: true)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
            return nil
        }
    }
    
  3. UIApplication 확장

    extension UIApplication {
    
        var snapshot: UIImage? {
            return keyWindow?.rootViewController?.view.snapshot
        }
    }
    

또는 iOS 10+에서는 새로운 UIGraphics ImageRenderrer + 권장되는 drawHierarchy를 사용할 수 있습니다.상황에 따라서는 layer보다 훨씬 빠를 수 있습니다.renderInContext

extension UIView {
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
        return renderer.image { _ in
            self.drawHierarchy(in: CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height), afterScreenUpdates: false)
        }
    }
}

@Bao Tuan Diep 감사합니다! 보충제를 추가하고 싶습니다.

코드를 사용하는 경우:

yourView.layer.render(in:UIGraphicsGetCurrentContext()!)

다음 점에 유의하십시오.

 - If you had used `autoLayout` or `Masonry` in `yourView` (that you want to convert) .
 - If you did not add `yourView` to another view which means that `yourView` was not used as a subview but just an object.

그럼 다음 명령을 사용해야 합니다.

[yourView setNeedsLayout];
[yourView layoutIfNeeded];

갱신하다yourView전에yourView.layer.render(in:UIGraphicsGetCurrentContext()!).

그렇지 않으면 요소가 포함되지 않은 이미지 개체를 얻을 수 있습니다.

스위프트 4.2

import Foundation
import UIKit  

extension UIImage {

    convenience init(view: UIView) {

        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
        view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)

    } 
}

사용:

img = UIImage.init(보기: self).홀더뷰)

Swift 3에서의 실장:

클래스 범위외에서 다음 코드를 추가합니다.

extension UIImage {
    convenience init(_ view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: (image?.cgImage)!)
    }
}

사용방법:

let image = UIImage( Your_View_Outlet )

일부에서 제안한 바와 같이 일반적인 경우로 적합할 수 있지만 뷰를 레이어로 그리는 방법이나 뷰의 서브뷰에 표시하려는 방법에 따라 모든 애플리케이션에서 이상적인 것은 아닙니다.

서브뷰 계층의 이미지를 작성하는 경우:

    let renderer = UIGraphicsImageRenderer(bounds: view.bounds)
    let image = renderer.image { ctx in
        self.drawHierarchy(in: self.bounds, afterScreenUpdates: 

그러나 보기가 하위 계층으로 구성된 경우, 예를 들어CALayer,포함하여CAShapeLayer로 구성되다UIBezierCurve...다음과 같은 것이 순서일 수 있습니다.

    let renderer = UIGraphicsImageRenderer(bounds: view.bounds)
    let image = renderer.image { rendererContext in
        for sublayer in self.layer.sublayers!.reversed() {
            sublayer.render(in: rendererContext.cgContext)
        }
    }

물론 하위 뷰가 레이어된 뷰를 표시할 수도 있습니다.그리고 그 이후로UIView.drawHierarchy()서브레이어를 포함하지 않음...더 복잡해질 수도 있고

작은 이미지(큰 이미지에는 사용할 수 없기 때문에)에 사용합니다.

extension UIView {
    public func drawHierarchyAsImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
        let image = renderer.image { _ in
            self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
        }
        return image
    }
}

고해상도 이미지의 경우 다음을 사용합니다.

extension UIView {
    public func renderAsImage(scale: CGFloat) -> UIImage {
        let format = UIGraphicsImageRendererFormat()
        format.scale = scale

        let renderer = UIGraphicsImageRenderer(bounds: bounds, format: format)
        return renderer.image { rendererContext in
            if let presentation = layer.presentation() {
                presentation.render(in: rendererContext.cgContext)
            }
        }
    }
}

뷰 계층에는 회전된 뷰가 있기 때문에 여기에 기재되어 있는 프레젠테이션레이어를 사용합니다.renderInContext는 회전된 서브뷰를 캡처하지 않습니다.

@Naveed J.의 메서드를 이렇게 구현했는데, 매우 효과가 있었습니다.

그의 익스텐션은 다음과 같습니다.

extension UIView {

    // Using a function since `var image` might conflict with an existing variable
    // (like on `UIImageView`)
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

구현 방법은 다음과 같습니다.

//create an image from yourView to display
//determine the frame of the view/imageimage
let screen = self.superview!.bounds
let width = screen.width / 4 //make image 1/4 width of screen
let height = width
let frame = CGRect(x: 0, y: 0, width: width, height: height)
let x = (screen.size.width - frame.size.width) * 0.5
let y = (screen.size.height - frame.size.height) * 0.5
let mainFrame = CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height)

let yourView = YourView() //instantiate yourView
yourView.frame = mainFrame //give it the frame
yourView.setNeedsDisplay() //tell it to display (I am not 100% sure this is needed)

let characterViewImage = yourView.asImage()

iOS 10 이후 새로운 UIGraphicsImageRenderer를 사용한 이니셜라이저:

extension UIImage{
    convenience init(view: UIView) {

    let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
    let canvas = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height)
    let image = renderer.image { _ in
        self.drawHierarchy(in: canvas, afterScreenUpdates: false)
    }
    self.init(cgImage: (image?.cgImage)!)
  }
}

나랑 잘 지내!

스위프트4

 extension UIView {

    func toImage() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
        self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
        let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return snapshotImageFromMyView!
    }

    }

뷰에 흐릿한 서브뷰가 포함되어 있는 경우(: UIVisualEffectView 인스턴스), drawViewHierarchyInRect:afterScreenUpdates만 작동합니다.

@ViJay Avhad의 답변은 이 경우 맞습니다.

뷰에 장면 키트 하위 뷰, 메탈 또는 스프라이트 키트 하위 뷰가 포함되어 있으면 UIGraphicsImageRenderer를 사용할 수 없습니다.이 경우,

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { ctx in
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}
please try below code.
-(UIImage *)getMainImageFromContext
{
UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0);
[viewBG.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}

언급URL : https://stackoverflow.com/questions/30696307/how-to-convert-a-uiview-to-an-image

반응형