Cara mengambil tangkapan layar secara terprogram di iOS

157

Saya ingin tangkapan layar gambar di layar disimpan ke perpustakaan foto yang disimpan.

Tusukan
sumber

Jawaban:

233

Mempertimbangkan pemeriksaan untuk tampilan retina gunakan cuplikan kode berikut:

#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");
}
DenNukem
sumber
13
Perhatikan bahwa ini tidak akan menangkap jenis konten layar tertentu, seperti lapisan OpenGL ES. UIGetScreenImage (), yang ditunjuk Hua-Ying, tidak.
Brad Larson
12
Orang-orang yang terkasih, jangan lupa untuk melakukan #import <QuartzCore / QuartzCore.h>
Enrico Susatyo
apakah ini akan mengambil tangkapan layar jika Anda melihat gambar yang baru saja diambil aplikasi Anda?
John Riselvato
5
Di mana gambar ini disimpan?
Burhanuddin Sunelwala
3
@ wladimir-palant: Bagaimana dengan Key-Board, Karena ketika saya gunakan untuk mengambil screen shot sceen di mana tipe pengguna, maka key board tidak menangkap, bagaimana saya bisa menambahkan key-Board dalam screen capture ..?
g212gs
46

Metode di bawah ini berfungsi untuk objek OPENGL juga

//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;
}
Mann
sumber
5
UIGetScreenImageadalah API pribadi
jonahb
Terima kasih banyak untuk ini! Anda pasti mendapatkan suara saya. Setelah mencoba beberapa cara lain, tampaknya drawViewHierarchy adalah satu-satunya cara bagaimana ambil layar dapat diambil dalam robovm dengan javafx ui.
Christo Smal
Inilah yang berfungsi setiap kali !!!! Saya punya banyak transformasi 3d pada scrreen dan solusi lain memang berantakan di screenshot saya. Ini berfungsi seperti seharusnya. Terima kasih banyak!
AndrewK
1
jika pengontrol tampilan berada dalam pengontrol navigasi, bilah navigasi tidak ditangkap
Radu Simionescu
Ya, drawViewHierarchyInRect lebih cepat dari renderInContext :-)
alones
20
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];
IOS Rocks
sumber
1
+1 Untuk catatan tentang penggunaan PNG. Ini lossless dan akan lebih kecil dari jpeg dengan kualitas = 1.0.
Rob
1
itu tidak mengambil NavigationBar di iOS 7 bukannya meninggalkan ruang kosong.
Ali Sufyan
14
- (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);  
}

Sumber .

Aistina
sumber
1
Mengapa myDataLength dikalikan dengan 4 di atas 320 * 480?
Jab
2
Ini juga benar-benar terlihat sangat bodoh karena mereka tidak memberi kita cara yang lebih mudah untuk melakukan ini.
Jab
320 * 480 adalah jumlah piksel. Kali empat sehingga Anda memiliki RGBA untuk setiap piksel.
Aistina
ingatlah untuk
menggandakannya
1
@Aistina, gunakan UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationDownMirrored];dan Anda tidak perlu 'buffer2' lagi. BTW bagi saya sepertinya Anda lupa tentang manajemen memori, tidak ada panggilan gratis () atau rilis () ...
Oleg Trakhman
10

DALAM 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
}
Vicky
sumber
9

Lihat ini posting sepertinya Anda dapat menggunakan UIGetScreenImage () untuk saat ini.

Hua-Ying
sumber
9
Ini tidak diperbolehkan lagi di iOS 4.
sudo rm -rf
9

Pada iOS10, ini menjadi sedikit lebih sederhana. UIKit hadir dengan UIGraphicsImageRenderyang memungkinkan Anda untuk melakukannya

... menyelesaikan tugas menggambar, tanpa harus menangani konfigurasi seperti kedalaman warna dan skala gambar, atau mengelola konteks Core Graphics

Apple Docs - UIGraphicsImageRenderer

Jadi sekarang Anda dapat melakukan sesuatu seperti ini:

let renderer = UIGraphicsImageRenderer(size: someView.bounds.size)

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

Banyak jawaban di sini bekerja untuk saya dalam banyak kasus. Tetapi ketika mencoba mengambil snapshot dari ARSCNView, saya hanya dapat melakukannya menggunakan metode yang dijelaskan di atas. Meskipun mungkin perlu dicatat bahwa saat ini, ARKit masih dalam versi beta dan Xcode dalam versi beta 4

Tulio Troncoso
sumber
7

Ini akan menyimpan tangkapan layar dan mengembalikan tangkapan layar juga.

-(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;
}
A. Adam
sumber
5

Saya pikir cuplikan berikut ini akan membantu jika Anda ingin mengambil layar penuh ( kecuali untuk status bar ), cukup ganti AppDelegate dengan nama delegasi aplikasi Anda jika perlu.

- (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;
}
tounaobun
sumber
Akhirnya yang menambahkan bilah navigasi! Akan memilih dua kali jika saya bisa! Cheers mate
marcelosarquis
4

Saya tidak dapat menemukan jawaban dengan implementasi Swift 3. Jadi begini.

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
}
jarora
sumber
3

Untuk iOS 7.0 atau lebih tinggi ..

Jika Anda ingin mengambil tangkapan layar tampilan say (myView), Anda dapat melakukan ini dengan satu baris:

[myView snapshotViewAfterScreenUpdates:NO];
sandeep gupta
sumber
3

Ini akan berfungsi dengan cepat 4.2 , tangkapan layar akan disimpan di perpustakaan, tapi jangan lupa untuk mengedit 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)

}
Hanya Lenz
sumber
2

Dapatkan Screenshot Dari Lihat

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

Simpan Gambar ke Foto

UIImageWriteToSavedPhotosAlbum(YOUR_IMAGE, nil, nil, nil);

Bagaimana-Untuk

UIImageWriteToSavedPhotosAlbum([self getScreenshotImage], nil, nil, nil);
Fernando Cervantes
sumber
2

Dapatkan Screenshot Dari Tampilan:

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

Harapan, inilah yang Anda cari. Kekhawatiran kembali ke saya. :)

Temui Doshi
sumber
2

Saya menjawab pertanyaan ini karena sangat dilihat, dan ada banyak jawaban di luar sana plus ada Swift dan Obj-C.

Penafian Ini bukan kode saya, atau jawaban saya, ini hanya untuk membantu orang yang mendarat di sini menemukan jawaban cepat. Ada tautan ke jawaban asli untuk memberikan kredit di mana kredit jatuh tempo !! Harap hormati jawaban asli dengan +1 jika Anda menggunakan jawaban mereka!


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

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

Catatan: Karena sifatnya dengan pemrograman, pembaruan mungkin perlu dilakukan, harap edit atau beri tahu saya! * Juga jika saya gagal memasukkan jawaban / metode yang berharga termasuk merasa bebas untuk memberi tahu saya juga!

Tusukan
sumber
1
Jawaban ini sepertinya tidak menambahkan apa pun. Anda hanya menyalin-menempelkan dua jawaban yang sudah ada di halaman dan memposting hasilnya sebagai milik Anda.
user2357112 mendukung Monica
Maksud saya bukan untuk mengambil pujian atas jawaban mereka, itu untuk memasukkan kedua cepat dan Obj-C dalam satu jawaban sehingga lebih cepat bagi orang untuk menemukan. Saya merujuk pada jawaban yang sesuai juga. jika ini tidak dilakukan saya akan menghapus jawaban saya dan kembali ke salah satu saja.
Jab
Saya menggunakan solusi ObjC. Bagi saya, saya harus menambahkan ".view" setelah "diri", tetapi hasilnya adalah 100%. Ini GOLD
samouray
Itu bekerja untuk Menangkap Stream Presentasi juga. Terima kasih
YSR fan
1

Pilihan lain adalah menggunakan alat Otomasi pada instrumen. Anda menulis skrip untuk menempatkan layar ke dalam apa pun yang Anda inginkan, kemudian mengambil gambar. Berikut ini skrip yang saya gunakan untuk salah satu aplikasi saya. Jelas, detail skrip akan berbeda untuk aplikasi Anda.

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");
William Jockusch
sumber
1

Dua opsi tersedia di situs di bawah ini:

OPSI 1: menggunakan UIWindow (dicoba dan bekerja dengan sempurna)

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

OPSI 2: menggunakan 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();

Untuk layar retina (seperti jawaban 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()];
    }

untuk detail lebih lanjut: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatically/

Nhat Dinh
sumber
1

Hanya sedikit kontribusi, saya sudah melakukan ini dengan tombol tetapi menekan juga berarti tombol ditangkap ditekan. Jadi pertama-tama saya membuka sorotan.

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

Saya mendapatkan kode utama dari: http://pinkstone.co.uk/how-to-take-a-screeshot-in-ios-programmatically/ di mana saya menggunakan opsi 1, opsi 2 sepertinya tidak berfungsi untuk saya. Menambahkan penyesuaian untuk ukuran layar Rentina dari utas ini, dan tidak menyoroti ScreenShotButton. Pandangan saya menggunakannya adalah layar StoryBoarded tombol dan label dan dengan beberapa UIView ditambahkan kemudian melalui program.

Symanski
sumber
Terima kasih the_UB untuk hasil editnya. Saya menyadari bahwa saya telah meninggalkan kode yang dikomentari, tetapi kemudian berpikir "begitulah asli kode yang ditempelkan". Kode kerja langsung yang sekarang ada di App Store.
Symanski
1

Di Swift Anda dapat menggunakan kode berikut.

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)
Mohammad Sadiq Shaikh
sumber
0

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
}
Chris Livdahl
sumber