如何在 iOS 上以编程方式截屏

我希望屏幕上的图像的屏幕截图保存到保存的照片库。

132308 次浏览
- (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);
}

来源

看看 这个后,它看起来像你可以使用 UIGetScreenImage()现在。

考虑检查 视网膜显示器,请使用以下代码片段:

#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");
}
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];

下面的方法也适用于 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;
}

这将保存一个截图,以及返回的截图。

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

我认为如果你想使用全屏(除了状态栏) ,下面的代码片段会有所帮助,如果有必要的话,只需用你的应用程序代理名称替换应用程序代理。

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

另一种选择是在仪器上使用自动化工具。你写一个脚本,把屏幕放入任何你想要的状态,然后拍摄。这是我用于我的一个应用程序的脚本。显然,这个脚本的细节对于你的应用程序来说是不同的。

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");

从视图获取屏幕截图

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

只是一个小贡献,我这样做了一个按钮,但按下也意味着按钮被捕获按下。所以首先我取消突出显示。

- (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 屏幕尺寸的调整,以及屏幕快照按钮的取消突出显示。我正在使用它的视图是一个 StoryBoards 屏幕的按钮和标签,并与几个 UIView 后来通过该程序添加。

以下网站提供两种选择:

选项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/

迅速

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 中,可以使用以下代码。

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)

IOS7.0或以上版本。

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

[myView snapshotViewAfterScreenUpdates:NO];

我在 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
}

从视图中截屏:

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

霍普,这就是你要找的东西。有任何问题请回复我。 :)

在 iOS10中,这变得更简单了

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

苹果文档-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测试阶段,这一点可能值得注意

迅捷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
}

我回答这个问题,因为它是一个高度评价,有许多答案,外加有斯威夫特和 Obj-C。

免责声明 这不是我的原则, 也没有我的答案, 这只是为了帮助在这里降落的人们找到一个快速的答案。有链接到原来的答案给予信贷的地方应得的信贷! ! < strong > 如果你使用原来的答案,请用 + 1表示尊敬!


使用 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");
}

在斯威夫特

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


}