मैं एक UIView का स्क्रीन शॉट कैसे ले सकता हूं?


133

मैं सोच रहा हूं कि कैसे मेरा iPhone ऐप विशिष्ट के UIViewरूप में स्क्रीन शॉट ले सकता है UIImage

मैंने इस कोड की कोशिश की लेकिन मुझे जो भी मिला वह एक कोरी छवि है।

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

myUIViewआयाम 320x480 है इसमें कुछ उप-विचार हैं। ऐसा करने का सही तरीका क्या है?


बस इसे बाहर की जाँच करें stackoverflow.com/a/44517922/3908884
मिलो तोशी

जवाबों:


73

मुझे लगता है कि आप चाहते हो सकते हैं renderInContext, नहीं drawInContext। drawInContext एक ऐसी विधि है जिसे आप ओवरराइड करेंगे ...

ध्यान दें कि यह सभी दृश्यों में काम नहीं कर सकता है, विशेष रूप से एक या एक साल पहले जब मैंने लाइव कैमरा दृश्य के साथ इसका उपयोग करने की कोशिश की तो यह काम नहीं किया।


हाय केंडल क्या आपके पास एक यूआईईवीई की सामग्री को अभी भी छवि के रूप में कैप्चर करने की सलाह नहीं है, लेकिन एक वीडियो के रूप में? आपके समय के लिए धन्यवाद! यहाँ प्रश्न: 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

अद्यतन के लिए अद्यतन : एक विस्तार जो ऐसा करता है:

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
निकोलस

इसने मेरी समस्या हल कर दी। मैं पुराने संस्करण का उपयोग कर रहा था और यह मुझे त्रुटियों का भार दे रहा था! धन्यवाद एक लाख
apinho

मैं एक दृश्य के स्क्रीन शॉट लेने के लिए उसी तरह का उपयोग कर रहा हूं। यदि किसी दृश्य में सबव्यू के रूप में wkwebview है, तो यह स्क्रीन शॉट लेने में सक्षम नहीं है। यह खाली दिखाता है। स्क्रीन शॉट को ठीक से कैसे लें?
ऋकेश सूबेदार

1
नियंत्रक दृश्य संक्रमण के दौरान इसे कॉल करने से संक्रमण समाप्त हो जाता है।
इयूलियन ओनोफ्रेई

63

आपको स्क्रीनशॉट या UIView के लिए मुख्य विंडो को कैप्चर करना होगा । आप इसे UIGraphicsBeginImageContextWithOptions का उपयोग करके रेटिना रिज़ॉल्यूशन में कर सकते हैं और इसके स्केल पैरामीटर 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();

यदि आपको ऐसा करने की आवश्यकता है तो ऐप के दस्तावेज़ फ़ोल्डर में 95% गुणवत्ता के साथ jpg प्रारूप में UIImage को बचाता है।

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

पूर्ण स्क्रीन स्क्रीनशॉट दुख की बात है स्थिति पट्टी पर कब्जा नहीं करता है। हालांकि बहुत अच्छा स्निपेट।
नेओनी

क्या कीबोर्ड पर कब्जा करने का कोई तरीका है?
mrvincenzo

@tibidabo धन्यवाद यह काम करता है। लेकिन मैं एक से अधिक छवि कैसे बचा सकता हूं?

"चेसापीक की महान मेमोरी लीक!" - हेमीज़ कॉनराड। (गंभीरता से, अपने सीजी को ठीक से प्रबंधित करें !!)
अल्बर्ट रेनशॉ

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 से नया एपीआई है

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

10

मैंने स्विफ्ट में स्क्रीनशॉट लेने के लिए UIView के लिए प्रयोग करने योग्य एक्सटेंशन बनाया है:

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 करता है।
माइक डेमिडोव

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

यह विधि आपके नियंत्रक वर्ग में रखी जा सकती है।


2
drawRectहै UIViewController (IIRC) का हिस्सा है। यह एक UIView का हिस्सा है। मुझे विश्वास नहीं है कि अगर नियंत्रक में यह कहा जाएगा।
jww

मैं सहेजे गए छवि पथ को कैसे प्राप्त कर सकता हूं?
GameDevGuru

5
CGImageRef UIGetScreenImage();

Apple अब हमें एक निजी एप्लिकेशन में इसका उपयोग करने की अनुमति देता है, भले ही यह एक निजी एपीआई हो


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()
    }
}

Main.storyboard

<?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>

परिणाम

यहाँ छवि विवरण दर्ज करें यहाँ छवि विवरण दर्ज करें


यह एक व्यापक उदाहरण है। उसके लिए आपका बहुत - बहुत धन्यवाद!
केएमसी

4

Apple अनुमति नहीं देता है:

CGImageRef UIGetScreenImage();

एप्लिकेशन drawRectको निर्दिष्ट तरीके से विधि का उपयोग करके स्क्रीनशॉट लेना चाहिए : http://developer.apple.com/library/ios/#qa/qa2010/qa1703.html


2
तो, मैट एस के जवाब के बारे में क्या?
गजेंद्र के चौहान

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 स्क्रीनशॉट अगर मैं एक खाली दृश्य मिलता है, लेकिन अगर मैं स्क्रीनशॉट स्क्रीनशॉट मैं क्या मुझे उम्मीद है?
अनोम

मैंने एक उदाहरण (UItableViewController) के साथ कोशिश की और यह काम करता है, हो सकता है कि समीक्षा के लिए अपना कोड यहां
रखें

चाल यह थी कि मुझे CGContextTranslateCTM (संदर्भ, 0, -view.frame.origin.y) का उपयोग करने की आवश्यकता थी;
अनोम

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.