Risposte:
Considerando un controllo per la visualizzazione della retina, utilizzare il seguente frammento di codice:
#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");
}
Il metodo seguente funziona anche con oggetti 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
è un'API privata
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];
- (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);
}
Fonte .
UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationDownMirrored];
e non hai più bisogno di 'buffer2'. A proposito, mi sembra di aver dimenticato la gestione della memoria, nessuna chiamata gratuita () o release () ...
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
}
Vedi questo post sembra che tu possa usare UIGetScreenImage () per ora.
A partire da iOS10, questo diventa un po 'più semplice. UIKit viene fornito con UIGraphicsImageRender
ciò che consente di
... eseguire attività di disegno, senza dover gestire configurazioni come la profondità del colore e la scala delle immagini, o gestire i contesti di grafica principale
Apple Docs - UIGraphicsImageRenderer
Quindi ora puoi fare qualcosa del genere:
let renderer = UIGraphicsImageRenderer(size: someView.bounds.size)
let image = renderer.image(actions: { context in
someView.drawHierarchy(in: someView.bounds, afterScreenUpdates: true)
})
Molte delle risposte qui hanno funzionato per me nella maggior parte dei casi. Ma quando ARSCNView
ho provato a scattare un'istantanea di un , sono stato in grado di farlo solo usando il metodo sopra descritto. Anche se potrebbe valere la pena notare che in questo momento, ARKit è ancora in beta e Xcode è in beta 4
Ciò salverà uno screenshot e restituirà anche lo screenshot.
-(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;
}
Penso che il seguente frammento sarebbe di aiuto se vuoi prendere uno schermo intero ( tranne la barra di stato ), se necessario sostituisci AppDelegate con il nome del delegato dell'app.
- (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;
}
Non sono riuscito a trovare una risposta con l'implementazione di Swift 3. Quindi eccolo qui.
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
}
Per iOS 7.0 o versioni successive.
Se vuoi prendere screenshot di view dire (myView), puoi farlo con una sola riga:
[myView snapshotViewAfterScreenUpdates:NO];
Funzionerà con swift 4.2 , lo screenshot verrà salvato in libreria, ma non dimenticare di modificare 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)
}
Ottieni screenshot dalla vista
-(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;
}
Salva immagine in foto
UIImageWriteToSavedPhotosAlbum(YOUR_IMAGE, nil, nil, nil);
Come
UIImageWriteToSavedPhotosAlbum([self getScreenshotImage], nil, nil, nil);
Ottieni screenshot dalla vista:
- (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
}
Spero, questo è quello che stai cercando. Qualsiasi preoccupazione mi risponda. :)
Sto rispondendo a questa domanda in quanto è molto apprezzato e ci sono molte risposte là fuori, oltre a Swift e Obj-C.
Disclaimer Questo non è il mio codice, né le mie risposte, questo è solo per aiutare le persone che arrivano qui a trovare una risposta rapida. Ci sono collegamenti alle risposte originali per dare credito dove il credito è dovuto !! Ti preghiamo di onorare le risposte originali con un +1 se usi la loro risposta!
#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
}
Nota: come per la natura con la programmazione, potrebbe essere necessario eseguire gli aggiornamenti , per favore modifica o fammi sapere! * Anche se non riuscissi a includere una risposta / un metodo degno di nota, sentiti libero di farmelo sapere!
Un'altra opzione è quella di utilizzare lo strumento di automazione sugli strumenti. Scrivi una sceneggiatura per mettere lo schermo in qualsiasi cosa tu voglia, quindi scatta le foto. Ecco lo script che ho usato per una delle mie app. Ovviamente, i dettagli dello script saranno diversi per la tua app.
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");
Due opzioni disponibili sul seguente sito:
OPZIONE 1: utilizzo di UIWindow (provato e perfettamente funzionante)
// 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();
OPZIONE 2: utilizzo di 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();
Per schermo retina (come risposta 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()];
}
per maggiori dettagli: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatical/
Solo un piccolo contributo, l'ho fatto con un pulsante ma la pressione significa anche che il pulsante viene acquisito premuto. Quindi, per prima cosa, desidero evidenziare.
- (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);
}
Ho ottenuto il corpo principale del codice da: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatical/ dove ho usato l'opzione 1, l'opzione 2 non sembra funzionare per me. Aggiunte le regolazioni per le dimensioni dello schermo di Rentina da questo thread e la non evidenziazione dello screenShotButton. La vista su cui lo sto usando è una schermata StoryBoarded di pulsanti ed etichette e con diverse UIView aggiunte in seguito tramite il programma.
In Swift è possibile utilizzare il seguente codice.
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)
Swift 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
}