Cara mengambil tangkapan layar secara terprogram di iOS


157

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

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

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

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];

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 .


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
}

9

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


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


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

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

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
}

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];

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)

}

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

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


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!


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

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/


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.


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)

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
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.