【问题标题】:How to take a screenshot programmatically on iOS如何在 iOS 上以编程方式截取屏幕截图
【发布时间】:2011-01-13 03:09:21
【问题描述】:

我想要将屏幕上的图像截屏保存到已保存的照片库中。

【问题讨论】:

    标签: ios iphone screenshot


    【解决方案1】:

    考虑检查 retina display 使用以下代码 sn-p:

    #import <QuartzCore/QuartzCore.h> 
    
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
    } else {
        UIGraphicsBeginImageContext(self.window.bounds.size);
    }
    
    [self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData *imageData = UIImagePNGRepresentation(image);
    if (imageData) {
        [imageData writeToFile:@"screenshot.png" atomically:YES];
    } else {
        NSLog(@"error while taking screenshot");
    }
    

    【讨论】:

    • 请注意,这不会捕获某些类型的屏幕内容,例如 OpenGL ES 层。华英所指的 UIGetScreenImage() 确实如此。
    • 亲爱的人们,别忘了做#import
    • 如果您正在查看您的应用刚刚拍摄的照片,这会截屏吗?
    • 这张图片存储在哪里?
    • @wladimir-palant : 键盘怎么样,因为当我用来截取用户输入的屏幕截图时,键盘没有捕获,我如何在屏幕截图中添加键盘。 .?
    【解决方案2】:

    以下方法也适用于 OPENGL 对象

    //iOS7 or above
    - (UIImage *) screenshot {
    
        CGSize size = CGSizeMake(your_width, your_height);
    
        UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
    
        CGRect rec = CGRectMake(0, 0, your_width, your_height);
        [_viewController.view drawViewHierarchyInRect:rec afterScreenUpdates:YES];
    
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    

    【讨论】:

    • UIGetScreenImage 是私有 API
    • 非常感谢!你肯定得到我的投票。在尝试了多种其他方式后,drawViewHierarchy 似乎是使用 javafx ui 在 robovm 中进行屏幕抓取的唯一方式。
    • 这就是每次都有效的方法!!!!我在屏幕上有很多 3d 转换,其他解决方案在我的屏幕截图中确实很混乱。这就像它应该的那样工作。非常感谢!
    • 如果视图控制器在导航控制器中,则导航栏不会被捕获
    • 是的,drawViewHierarchyInRect 比 renderInContext 快:-)
    【解决方案3】:
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
    [self.myView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    NSData *imageData = UIImageJPEGRepresentation(image, 1.0 ); //you can use PNG too
    [imageData writeToFile:@"image1.jpeg" atomically:YES];
    

    【讨论】:

    • +1 关于使用 PNG 的说明。它是无损的,并且会小于质量 = 1.0 的 jpeg。
    • 它没有在 iOS 7 中使用 NavigationBar,而是留下空白。
    【解决方案4】:
    - (UIImage*) getGLScreenshot {
        NSInteger myDataLength = 320 * 480 * 4;
    
        // allocate array and read pixels into it.
        GLubyte *buffer = (GLubyte *) malloc(myDataLength);
        glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    
        // gl renders "upside down" so swap top to bottom into new array.
        // there's gotta be a better way, but this works.
        GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
        for(int y = 0; y <480; y++)
        {
            for(int x = 0; x <320 * 4; x++)
            {
                buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + x];
            }
        }
    
        // make data provider with data.
        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
    
        // prep the ingredients
        int bitsPerComponent = 8;
        int bitsPerPixel = 32;
        int bytesPerRow = 4 * 320;
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
        CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    
        // make the cgimage
        CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
    
        // then make the uiimage from that
        UIImage *myImage = [UIImage imageWithCGImage:imageRef];
        return myImage;
    }
    
    - (void)saveGLScreenshotToPhotosAlbum {
        UIImageWriteToSavedPhotosAlbum([self getGLScreenshot], nil, nil, nil);  
    }
    

    Source.

    【讨论】:

    • 为什么 myDataLength 在 320 * 480 上乘以 4?
    • 这也确实看起来很愚蠢,因为他们没有为我们提供更简单的方法。
    • 320 * 480 是像素数。乘以四,因此每个像素都有 RGBA。
    • 记得在 iPhone 4 上运行时按比例因子倍增 :-)
    • @Aistina ,使用 UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationDownMirrored]; 并且您不再需要“buffer2”。顺便说一句,在我看来,您似乎忘记了内存管理,没有 free() 或 release() 调用...
    【解决方案5】:

    迅速

    func captureScreen() -> UIImage
    {
    
        UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0);
    
        self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
    
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    
        UIGraphicsEndImageContext()
    
        return image
    }
    

    【讨论】:

      【解决方案6】:

      从 iOS10 开始,这变得更简单了。 UIKit 带有UIGraphicsImageRender,可以让你

      ...完成绘图任务,无需处理颜色深度和图像比例等配置,或管理核心图形上下文

      Apple Docs - UIGraphicsImageRenderer

      所以你现在可以这样做:

      let renderer = UIGraphicsImageRenderer(size: someView.bounds.size)
      
      let image = renderer.image(actions: { context in
          someView.drawHierarchy(in: someView.bounds, afterScreenUpdates: true)
      })
      

      在大多数情况下,这里的许多答案都对我有用。但是当尝试拍摄ARSCNView 的快照时,我只能使用上述方法进行拍摄。虽然可能值得注意的是,此时 ARKit 仍处于 beta 阶段,Xcode 处于 beta 4 阶段

      【讨论】:

        【解决方案7】:

        请参阅this 发布的帖子,看起来您现在可以使用UIGetScreenImage()。

        【讨论】:

        • 这在 iOS 4 中是不允许的。
        【解决方案8】:

        这将保存屏幕截图并返回屏幕截图。

        -(UIImage *)capture{
            UIGraphicsBeginImageContext(self.view.bounds.size);
            [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
            UIImage *imageView = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            UIImageWriteToSavedPhotosAlbum(imageView, nil, nil, nil); //if you need to save
            return imageView;
        }
        

        【讨论】:

          【解决方案9】:

          如果你想全屏显示,我认为下面的 sn-p 会有所帮助(状态栏除外),如有必要,只需将 AppDelegate 替换为你的应用代理名称即可。

          - (UIImage *)captureFullScreen {
          
              AppDelegate *_appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
          
              if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
                  // for retina-display
                  UIGraphicsBeginImageContextWithOptions(_appDelegate.window.bounds.size, NO, [UIScreen mainScreen].scale);
                  [_appDelegate.window drawViewHierarchyInRect:_appDelegate.window.bounds afterScreenUpdates:NO];
              } else {
                  // non-retina-display
                  UIGraphicsBeginImageContext(_bodyView.bounds.size);
                  [_appDelegate.window drawViewHierarchyInRect:_appDelegate.window.bounds afterScreenUpdates:NO];
              }
          
              UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
              UIGraphicsEndImageContext();
              return image;
          }
          

          【讨论】:

          • 终于添加了导航栏!如果可以的话,我会投票两次!干杯队友
          【解决方案10】:

          我找不到 Swift 3 实现的答案。就这样吧。

          static func screenshotOf(window: UIWindow) -> UIImage? {
          
              UIGraphicsBeginImageContextWithOptions(window.bounds.size, true, UIScreen.main.scale)
          
              guard let currentContext = UIGraphicsGetCurrentContext() else {
                  return nil
              }
          
              window.layer.render(in: currentContext)
              guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
                  UIGraphicsEndImageContext()
                  return nil
              }
          
              UIGraphicsEndImageContext()
              return image
          }
          

          【讨论】:

            【解决方案11】:

            这适用于swift 4.2,截图将保存在库中,但请不要忘记编辑info.plist @ NSPhotoLibraryAddUsageDescription

              @IBAction func takeScreenshot(_ sender: UIButton) {
            
                //Start full Screenshot
                print("full Screenshot")
                UIGraphicsBeginImageContext(card.frame.size)
                view.layer.render(in: UIGraphicsGetCurrentContext()!)
                var sourceImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                UIImageWriteToSavedPhotosAlbum(sourceImage!, nil, nil, nil)
            
                //Start partial Screenshot
                print("partial Screenshot")
                UIGraphicsBeginImageContext(card.frame.size)
                sourceImage?.draw(at: CGPoint(x:-25,y:-100)) //the screenshot starts at -25, -100
                var croppedImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                UIImageWriteToSavedPhotosAlbum(croppedImage!, nil, nil, nil)
            
            }
            

            【讨论】:

              【解决方案12】:

              适用于 iOS 7.0 或更高版本..

              如果你想截取视图say(myView)的截图,你可以用单行来做:

              [myView snapshotViewAfterScreenUpdates:NO];
              

              【讨论】:

                【解决方案13】:

                我正在回答这个问题,因为它受到高度关注,并且有很多答案,还有 Swift 和 Obj-C。

                免责声明 这不是我的代码, 也不是我的答案, 这只是为了帮助登陆这里的人快速找到回答。有指向原始答案的链接,以便在应得的地方给予信用! 如果您使用他们的答案,请用 +1 尊重原始答案!


                Using QuartzCore

                #import <QuartzCore/QuartzCore.h> 
                
                if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
                    UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
                } else {
                    UIGraphicsBeginImageContext(self.window.bounds.size);
                }
                
                [self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
                UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
                UIGraphicsEndImageContext();
                NSData *imageData = UIImagePNGRepresentation(image);
                if (imageData) {
                    [imageData writeToFile:@"screenshot.png" atomically:YES];
                } else {
                    NSLog(@"error while taking screenshot");
                }
                

                In Swift

                func captureScreen() -> UIImage
                {
                
                    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0);
                
                    self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
                
                    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
                
                    UIGraphicsEndImageContext()
                
                    return image
                }
                

                注意: 由于编程的本质, 可能需要进行更新,所以请编辑或让我知道! *另外,如果我未能包含值得包含的答案/方法,也请随时告诉我!

                【讨论】:

                • 这个答案似乎没有添加任何东西。您只需复制粘贴页面上已有的两个答案并将结果作为您自己的结果发布。
                • 我的本意不是要归功于他们的答案,而是将 swift 和 Obj-C 都包含在一个答案中,以便人们更快地找到。我也参考了相应的答案。如果不应该这样做,我将删除我的答案并恢复到其中一个。
                • 我正在使用 ObjC 解决方案。对我来说,我不得不在“self”之后添加“.view”,但结果是 100%。这是黄金
                • 它也适用于捕获演示流。谢谢
                【解决方案14】:

                从视图中获取屏幕截图

                -(UIImage *)getScreenshotImage {
                    if ([[UIScreen mainScreen] scale] == 2.0) {
                        UIGraphicsBeginImageContextWithOptions(self.view.frame.size, FALSE, 2.0);
                    } else {
                        UIGraphicsBeginImageContextWithOptions(self.view.frame.size, FALSE, 1.0);
                    }
                
                    [self.view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
                
                    UIImage * result = UIGraphicsGetImageFromCurrentImageContext();
                    UIGraphicsEndImageContext();
                
                    return result;
                }
                

                将图像保存到照片

                UIImageWriteToSavedPhotosAlbum(YOUR_IMAGE, nil, nil, nil);
                

                操作方法

                UIImageWriteToSavedPhotosAlbum([self getScreenshotImage], nil, nil, nil);
                

                【讨论】:

                  【解决方案15】:

                  从视图中获取屏幕截图:

                  - (UIImage *)takeSnapshotView {
                      CGRect rect = [myView bounds];//Here you can change your view with myView
                      UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
                      CGContextRef context = UIGraphicsGetCurrentContext();
                      [myView.layer renderInContext:context];
                      UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
                      UIGraphicsEndImageContext();
                  
                      return capturedScreen;//capturedScreen is the image of your view
                  }
                  

                  希望,这就是您要找的。任何问题都可以回复我。 :)

                  【讨论】:

                    【解决方案16】:

                    另一种选择是在仪器上使用自动化工具。您编写一个脚本将屏幕放入您想要的任何状态,然后拍摄。这是我用于我的一个应用程序的脚本。显然,脚本的详细信息会因您的应用而异。

                    var target = UIATarget.localTarget();
                    var app = target.frontMostApp();
                    var window = app.mainWindow();
                    var picker = window.pickers()[0];
                    var wheel = picker.wheels()[2];
                    var buttons = window.buttons();
                    var button1 = buttons.firstWithPredicate("name == 'dateButton1'");
                    var button2 = buttons.firstWithPredicate("name == 'dateButton2'");
                    
                    function setYear(picker, year) {
                        var yearName = year.toString();
                        var yearWheel = picker.wheels()[2];
                        yearWheel.selectValue(yearName);
                    }
                    
                    function setMonth(picker, monthName) {
                        var wheel = picker.wheels()[0];
                        wheel.selectValue(monthName);
                    }
                    
                    function setDay(picker, day) {
                        var wheel = picker.wheels()[1];
                        var name = day.toString();
                        wheel.selectValue(name);
                    }
                    
                    target.delay(1);
                    setYear(picker, 2015);
                    setMonth(picker, "July");
                    setDay(picker, 4);
                    button1.tap();
                    setYear(picker, 2015);
                    setMonth(picker, "December");
                    setDay(picker, 25);
                    
                    target.captureScreenWithName("daysShot1");
                    
                    var nButtons = buttons.length;
                    UIALogger.logMessage(nButtons + " buttons");
                    for (var i=0; i<nButtons; i++) {
                        UIALogger.logMessage("button " + buttons[i].name());
                    }
                    
                    var tabBar = window.tabBars()[0];
                    var barButtons = tabBar.buttons();
                    
                    var nBarButtons = barButtons.length;
                    UIALogger.logMessage(nBarButtons + " buttons on tab bar");
                    
                    for (var i=0; i<nBarButtons; i++) {
                        UIALogger.logMessage("button " + barButtons[i].name());
                    }
                    
                    var weeksButton = barButtons[1];
                    var monthsButton = barButtons[2];
                    var yearsButton = barButtons[3];
                    
                    target.delay(2);
                    weeksButton.tap();
                    target.captureScreenWithName("daysShot2");
                    target.delay(2);
                    monthsButton.tap();
                    target.captureScreenWithName("daysShot3");
                    target.delay(2);
                    yearsButton.tap();
                    target.delay(2);
                    button2.tap();
                    target.delay(2);
                    setYear(picker, 2018);
                    target.delay(2);
                    target.captureScreenWithName("daysShot4");
                    

                    【讨论】:

                      【解决方案17】:

                      以下网站提供两个选项:

                      选项 1:使用 UIWindow(尝试过并且完美运行)

                      // create graphics context with screen size
                      CGRect screenRect = [[UIScreen mainScreen] bounds];
                      UIGraphicsBeginImageContext(screenRect.size);
                      CGContextRef ctx = UIGraphicsGetCurrentContext();
                      [[UIColor blackColor] set];
                      CGContextFillRect(ctx, screenRect);
                      
                      // grab reference to our window
                      UIWindow *window = [UIApplication sharedApplication].keyWindow;
                      
                      // transfer content into our context
                      [window.layer renderInContext:ctx];
                      UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
                      UIGraphicsEndImageContext();
                      

                      选项 2:使用 UIView

                      // grab reference to the view you'd like to capture
                      UIView *wholeScreen = self.splitViewController.view;
                      
                      // define the size and grab a UIImage from it
                      UIGraphicsBeginImageContextWithOptions(wholeScreen.bounds.size, wholeScreen.opaque, 0.0);
                      [wholeScreen.layer renderInContext:UIGraphicsGetCurrentContext()];
                      UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
                      UIGraphicsEndImageContext();
                      

                      对于视网膜屏幕(作为 DenNukem 的回答)

                      // grab reference to our window
                          UIWindow *window = [UIApplication sharedApplication].keyWindow;
                      
                          // create graphics context with screen size
                          CGRect screenRect = [[UIScreen mainScreen] bounds];
                          if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
                              UIGraphicsBeginImageContextWithOptions(screenRect.size, NO, [UIScreen mainScreen].scale);
                          } else {
                              UIGraphicsBeginImageContext(screenRect.size);
                              [window.layer renderInContext:UIGraphicsGetCurrentContext()];
                          }
                      

                      更多详情: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatically/

                      【讨论】:

                        【解决方案18】:

                        只是一个小小的贡献,我用一个按钮完成了这个,但按下也意味着按钮被按下。所以首先我取消突出显示。

                        - (IBAction)screenShot:(id)sender {
                            // Unpress screen shot button
                            screenShotButton.highlighted = NO;
                        
                            // create graphics context with screen size
                            CGRect screenRect = [[UIScreen mainScreen] bounds];
                        
                            if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
                                UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
                            } else {
                                UIGraphicsBeginImageContext(self.view.bounds.size);
                            }
                        
                            CGContextRef ctx = UIGraphicsGetCurrentContext();
                            [[UIColor blackColor] set];
                            CGContextFillRect(ctx, screenRect);
                        
                            // grab reference to our window
                            UIWindow *window = [UIApplication sharedApplication].keyWindow;
                        
                            // transfer content into our context
                            [window.layer renderInContext:ctx];
                            UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
                            UIGraphicsEndImageContext();
                        
                            // save screengrab to Camera Roll
                            UIImageWriteToSavedPhotosAlbum(screengrab, nil, nil, nil);
                        }
                        

                        我的代码主体来自: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatically/ 在我使用选项 1 的地方,选项 2 似乎对我不起作用。从这个线程添加了对 Rentina 屏幕尺寸的调整,以及 screenShotButton 的取消突出显示。我使用它的视图是一个由按钮和标签组成的 StoryBoarded 屏幕,稍后通过程序添加了几个 UIView。

                        【讨论】:

                        • 感谢 the_UB 的编辑。我意识到我留下了注释代码,但后来想“这就是粘贴代码的真实性”。现在在 App Store 中的实时工作代码。
                        【解决方案19】:

                        在 Swift 中您可以使用以下代码。

                        if UIScreen.mainScreen().respondsToSelector(Selector("scale")) {
                            UIGraphicsBeginImageContextWithOptions(self.window!.bounds.size, false, UIScreen.mainScreen().scale)
                        }
                        else{
                            UIGraphicsBeginImageContext(self.window!.bounds.size)
                        }
                        self.window?.layer.renderInContext(UIGraphicsGetCurrentContext())
                        var image : UIImage = UIGraphicsGetImageFromCurrentImageContext()
                        UIGraphicsEndImageContext()
                        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
                        

                        【讨论】:

                          【解决方案20】:

                          斯威夫特 4:

                          func makeImage(withView view: UIView) -> UIImage? {
                          
                              let rect = view.bounds
                          
                              UIGraphicsBeginImageContextWithOptions(rect.size, true, 0)
                          
                              guard let context = UIGraphicsGetCurrentContext() else {
                                assertionFailure()
                                return nil
                              }
                          
                              view.layer.render(in: context)
                          
                              guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
                                assertionFailure()
                                return nil
                              }
                          
                              UIGraphicsEndImageContext()
                          
                              return image
                          }
                          

                          【讨论】:

                            猜你喜欢
                            • 2016-03-18
                            • 1970-01-01
                            • 2023-03-19
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2011-11-22
                            • 1970-01-01
                            • 2011-04-06
                            相关资源
                            最近更新 更多