UIView의 스크린 샷을 어떻게 찍습니까?


133

내 아이폰의 애플 리케이션이 특정의 스크린 샷이 걸릴 수 있는지 궁금 UIViewA와를 UIImage.

이 코드를 시도했지만 빈 이미지 만 있습니다.

UIGraphicsBeginImageContext(CGSizeMake(320,480));
CGContextRef context = UIGraphicsGetCurrentContext();
[myUIView.layer drawInContext:context];
UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

myUIView320x480 크기이며 일부 하위 뷰가 있습니다. 이를 수행하는 올바른 방법은 무엇입니까?


답변:


73

나는 당신이 원하는 renderInContext것이 아니라고 생각합니다 drawInContext. drawInContext는 더 많은 메소드입니다.

라이브 뷰에서 이것을 사용하려고 시도했을 때 특히 1 년 정도 전에 모든 뷰에서 작동하지 않을 수도 있습니다.


안녕하세요 Kendall UIView의 내용을 스틸 이미지가 아니라 비디오로 캡처하는 데 대한 조언이 있습니까? 시간 내 줘서 고마워! 여기 질문 : stackoverflow.com/questions/34956713/...
Crashalot

187

iOS 7에는 현재 그래픽 컨텍스트에 뷰 계층을 그릴 수있는 새로운 방법이 있습니다. UIImage를 매우 빠르게 얻는 데 사용할 수 있습니다.

UIView뷰를 다음과 같이 얻기 위해 카테고리 메소드를 구현 했습니다 UIImage.

- (UIImage *)pb_takeSnapshot {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);

    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];

    // old style [self.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

기존 renderInContext:방법 보다 훨씬 빠릅니다 .

참조 : https://developer.apple.com/library/content/qa/qa1817/_index.html

SWIFT 업데이트 : 동일한 기능을 수행하는 확장 프로그램 :

extension UIView {

    func pb_takeSnapshot() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)

        drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)

        // old style: layer.renderInContext(UIGraphicsGetCurrentContext())

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

스위프트 3 업데이트

    UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)

    drawHierarchy(in: self.bounds, afterScreenUpdates: true)

    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image

당신은 큰 UILabel의 또는 CAShapeLayer이있는 경우,이 작품은, 그것을 그리기 아무것도하지 끝하지 않습니다
jjxtra

신속한 스 니펫 덕분에 내 문제를 해결했습니다 : stackoverflow.com/a/27764590/1139044 .
Nicholas

내 문제를 해결했다. 이전 버전을 사용하고 있었고 많은 오류가 발생했습니다! 감사합니다 백만
apinho

뷰의 스크린 샷을 찍는 것과 같은 방법을 사용하고 있습니다. 뷰에 wkwebview가 서브 뷰로 있으면 스크린 샷을 찍을 수 없습니다. 공백으로 표시됩니다. 스크린 샷을 올바르게 찍는 방법?
Rikesh Subedi

1
뷰 컨트롤러 전환 중에 이것을 호출하면 전환 끝이 깜박입니다.
Iulian Onofrei

63

스크린 샷 또는 UIView 의 키 창 을 캡처해야합니다 . UIGraphicsBeginImageContextWithOptions를 사용하여 Retina Resolution 에서이를 수행 하고 스케일 매개 변수를 0.0f로 설정할 수 있습니다 . 항상 기본 해상도 (iPhone 4 이상의 레티 나)로 캡처합니다.

이것은 전체 화면 스크린 샷 (키 창)을 수행합니다.

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CGRect rect = [keyWindow bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[keyWindow.layer renderInContext:context];   
UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

이 코드는 기본 해상도로 UIView를 캡처합니다.

CGRect rect = [captureView bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[captureView.layer renderInContext:context];   
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

이렇게하면 UIImage를 필요한 경우 앱의 문서 폴더에 jpg 형식의 95 % 품질로 저장합니다.

NSString  *imagePath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/capturedImage.jpg"]];    
[UIImageJPEGRepresentation(capturedImage, 0.95) writeToFile:imagePath atomically:YES];

전체 화면 스크린 샷이 슬프게도 상태 표시 줄을 캡처하지 않습니다. 그래도 아주 좋은 발췌 문장.
neoneye

키보드를 캡처 할 수있는 방법이 있습니까?
mrvincenzo

@tibidabo 감사합니다. 그러나 둘 이상의 이미지를 어떻게 저장할 수 있습니까?
josef

"체사 피크의 위대한 메모리 누수!" -헤르메스 콘래드 (그렇지만 CG를 올바르게 관리하십시오 !!)
Albert Renshaw

22

iOS7부터 기본 방법은 다음과 같습니다.

- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates

위의 메서드를 호출하면 현재 뷰의 내용을 비트 맵 이미지로 직접 렌더링하는 것보다 빠릅니다.

흐림과 같은 그래픽 효과를 스냅 샷에 적용하려면이 drawViewHierarchyInRect:afterScreenUpdates:방법을 대신 사용하십시오 .

https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html


13

iOS 10의 새로운 API가 있습니다

extension UIView {
    func makeScreenshot() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
        return renderer.image { (context) in
            self.layer.render(in: context.cgContext)
        }
    }
}

10

UIView가 Swift에서 스크린 샷을 찍을 수있는 유용한 확장 프로그램을 만들었습니다.

extension UIView{

var screenshot: UIImage{

    UIGraphicsBeginImageContext(self.bounds.size);
    let context = UIGraphicsGetCurrentContext();
    self.layer.renderInContext(context)
    let screenShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return screenShot
}
}

사용하려면 다음을 입력하십시오.

let screenshot = view.screenshot

1
장치의 올바른 배율을 사용하는 UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0);대신 사용하십시오 UIGraphicsBeginImageContext(self.bounds.size);.
knshn

1
작동하지만 확인하는 drawViewHierarchyInRect대신 사용 renderInContext 하지 않습니다.
Mike Demidov

7
- (void)drawRect:(CGRect)rect {
  UIGraphicsBeginImageContext(self.bounds.size);    
  [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
  UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);  
}

이 메소드는 Controller 클래스에 넣을 수 있습니다.


2
drawRectUIViewController (IIRC)의 일부 가 아닙니다 . UIView의 일부입니다. 나는 그것이 컨트롤러에 있으면 호출 될 것이라고 믿지 않습니다.
jww

저장된 이미지 경로를 얻으려면 어떻게해야합니까?
GameDevGuru

5
CGImageRef UIGetScreenImage();

Apple은 이제 개인 API이지만 공개 응용 프로그램에서 사용할 수 있습니다.


myUIView 위에 캡처하고 싶지 않은 다른 UIView가 있습니다. 그렇지 않으면 이것은 좋을 것입니다.
cduck

5

세부

  • Xcode 버전 10.3 (10G8), 스위프트 5

해결책

import UIKit

extension CALayer {
    func makeSnapshot() -> UIImage? {
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
        defer { UIGraphicsEndImageContext() }
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        render(in: context)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        return screenshot
    }
}

extension UIView {
    func makeSnapshot() -> UIImage? {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(size: frame.size)
            return renderer.image { _ in drawHierarchy(in: bounds, afterScreenUpdates: true) }
        } else {
            return layer.makeSnapshot()
        }
    }
}

용법

let image = view.makeSnapshot()

전체 샘플

여기에 솔루션 코드추가하는 것을 잊지 마십시오

import UIKit

class ViewController: UIViewController {

    @IBOutlet var viewForScreenShot: UIView!
    @IBOutlet var screenShotRenderer: UIImageView!

    @IBAction func makeViewScreenShotButtonTapped2(_ sender: UIButton) {
        screenShotRenderer.image = viewForScreenShot.makeSnapshot()
    }
}

메인 스토리

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_2214957" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Acg-GO-mMN">
                                <rect key="frame" x="67" y="28" width="240" height="128"/>
                                <subviews>
                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="4Fr-O3-56t">
                                        <rect key="frame" x="72" y="49" width="96" height="30"/>
                                        <constraints>
                                            <constraint firstAttribute="height" constant="30" id="cLv-es-h7Q"/>
                                            <constraint firstAttribute="width" constant="96" id="ytF-FH-gdm"/>
                                        </constraints>
                                        <nil key="textColor"/>
                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                        <textInputTraits key="textInputTraits"/>
                                    </textField>
                                </subviews>
                                <color key="backgroundColor" red="0.0" green="0.47843137250000001" blue="1" alpha="0.49277611300000002" colorSpace="custom" customColorSpace="sRGB"/>
                                <color key="tintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
                                <constraints>
                                    <constraint firstItem="4Fr-O3-56t" firstAttribute="centerX" secondItem="Acg-GO-mMN" secondAttribute="centerX" id="egj-rT-Gz5"/>
                                    <constraint firstItem="4Fr-O3-56t" firstAttribute="centerY" secondItem="Acg-GO-mMN" secondAttribute="centerY" id="ymi-Ll-WIV"/>
                                </constraints>
                            </view>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SQq-IE-pvj">
                                <rect key="frame" x="109" y="214" width="157" height="30"/>
                                <state key="normal" title="make view screen shot"/>
                                <connections>
                                    <action selector="makeViewScreenShotButtonTapped2:" destination="BYZ-38-t0r" eventType="touchUpInside" id="KSY-ec-uvA"/>
                                </connections>
                            </button>
                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="CEZ-Ju-Tpq">
                                <rect key="frame" x="67" y="269" width="240" height="128"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="240" id="STo-iJ-rM4"/>
                                    <constraint firstAttribute="height" constant="128" id="tfi-zF-zdn"/>
                                </constraints>
                            </imageView>
                        </subviews>
                        <color key="backgroundColor" red="0.95941069162436543" green="0.95941069162436543" blue="0.95941069162436543" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="CEZ-Ju-Tpq" firstAttribute="top" secondItem="SQq-IE-pvj" secondAttribute="bottom" constant="25" id="6x1-iB-gKF"/>
                            <constraint firstItem="Acg-GO-mMN" firstAttribute="leading" secondItem="CEZ-Ju-Tpq" secondAttribute="leading" id="LUp-Be-FiC"/>
                            <constraint firstItem="SQq-IE-pvj" firstAttribute="top" secondItem="Acg-GO-mMN" secondAttribute="bottom" constant="58" id="Qu0-YT-k9O"/>
                            <constraint firstItem="Acg-GO-mMN" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="Qze-zd-ajY"/>
                            <constraint firstItem="Acg-GO-mMN" firstAttribute="trailing" secondItem="CEZ-Ju-Tpq" secondAttribute="trailing" id="b1d-sp-GHD"/>
                            <constraint firstItem="SQq-IE-pvj" firstAttribute="centerX" secondItem="CEZ-Ju-Tpq" secondAttribute="centerX" id="qCL-AF-Cro"/>
                            <constraint firstItem="Acg-GO-mMN" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="8" symbolic="YES" id="u5Y-eh-oSG"/>
                            <constraint firstItem="CEZ-Ju-Tpq" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="vkx-JQ-pOF"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="screenShotRenderer" destination="CEZ-Ju-Tpq" id="8QB-OE-ib6"/>
                        <outlet property="viewForScreenShot" destination="Acg-GO-mMN" id="jgL-yn-8kk"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="32.799999999999997" y="37.331334332833585"/>
        </scene>
    </scenes>
</document>

결과

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


이것은 포괄적 인 예입니다. 정말 감사합니다!
KMC


4

UIView에서 스크린 샷을 저장하기 위해이 확장을 만들었습니다.

extension UIView {
func saveImageFromView(path path:String) {
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)
    drawViewHierarchyInRect(bounds, afterScreenUpdates: true)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    UIImageJPEGRepresentation(image, 0.4)?.writeToFile(path, atomically: true)

}}

전화 :

let pathDocuments = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).first!
let pathImage = "\(pathDocuments)/\(user!.usuarioID.integerValue).jpg"
reportView.saveImageFromView(path: pathImage)

png를 만들려면 다음을 변경해야합니다.

UIImageJPEGRepresentation(image, 0.4)?.writeToFile(path, atomically: true)

으로

UIImagePNGRepresentation(image)?.writeToFile(path, atomically: true)

UITableViewCell을 스크린 샷하면 왜 빈보기가 표시되지만 tableView를 스크린 샷하면 내가 기대하는 것을 얻습니까?
Unome

나는 예제 (UItableViewController)를 사용해 보았으며 작동 할 수도 있습니다. 검토를 위해 여기에 코드를 넣으십시오.
anthonyqz

비결은 CGContextTranslateCTM (context, 0, -view.frame.origin.y)를 사용해야한다는 것입니다.
Unome

3

스위프트 4 업데이트 :

extension UIView {
   var screenShot: UIImage?  {
        if #available(iOS 10, *) {
            let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
            return renderer.image { (context) in
                self.layer.render(in: context.cgContext)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(bounds.size, false, 5);
            if let _ = UIGraphicsGetCurrentContext() {
                drawHierarchy(in: bounds, afterScreenUpdates: true)
                let screenshot = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return screenshot
            }
            return nil
        }
    }
}

이 스크린 샷 방법은 훌륭했습니다.
eonist

2

다음 스 니펫은 스크린 샷을 찍는 데 사용됩니다.

UIGraphicsBeginImageContext(self.muUIView.bounds.size);

[myUIView.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

사용 renderInContext:하는 대신 방법 drawInContext:방법

renderInContext:메소드는 수신자와 해당 하위 계층을 현재 컨텍스트로 렌더링합니다. 이 방법은 레이어 트리에서 직접 렌더링합니다.


1
-(UIImage *)convertViewToImage
{
    UIGraphicsBeginImageContext(self.bounds.size);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

  return image;
}

0

다음 UIView 카테고리를 사용할 수 있습니다-

@implementation UIView (SnapShot)

 - (UIImage *)snapshotImage
{
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);        
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];        
    // old style [self.layer renderInContext:UIGraphicsGetCurrentContext()];        
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();        
    UIGraphicsEndImageContext();        
    return image;
}    
@end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.