Saya ingin mengonversi UIView menjadi gambar dan menyimpannya di aplikasi saya. Bisakah seseorang memberi tahu saya cara mengambil tangkapan layar dari suatu tampilan atau mengonversinya menjadi gambar dan apa cara terbaik untuk menyimpannya dalam aplikasi (Bukan rol kamera)? Ini kode untuk tampilan tersebut:
var overView = UIView(frame: CGRectMake(0, 0, self.view.frame.width/1.3, self.view.frame.height/1.3))
overView.center = CGPointMake(CGRectGetMidX(self.view.bounds),
CGRectGetMidY(self.view.bounds)-self.view.frame.height/16);
overView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(overView)
self.view.bringSubviewToFront(overView)
ios
swift
uiview
screenshot
Sameer Hussain
sumber
sumber
Jawaban:
Perpanjangan
UIView
harus melakukan trik.extension UIView { // Using a function since `var image` might conflict with an existing variable // (like on `UIImageView`) func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } }
Apple melarang penggunaan
UIGraphicsBeginImageContext
mulai iOS 10 dengan pengenalan gamut warna P3.UIGraphicsBeginImageContext
hanya sRGB dan 32-bit. Mereka memperkenalkanUIGraphicsImageRenderer
API baru yang sepenuhnya dikelola dengan warna, berbasis blok, memiliki subkelas untuk PDF dan gambar, dan secara otomatis mengelola seumur hidup konteks. Lihat WWDC16 sesi 205 untuk lebih jelasnya (rendering gambar dimulai sekitar tanda 11:50)Untuk memastikannya berfungsi di setiap perangkat, gunakan
#available
dengan fallback ke versi iOS yang lebih lama:extension UIView { // Using a function since `var image` might conflict with an existing variable // (like on `UIImageView`) func asImage() -> UIImage { if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } else { UIGraphicsBeginImageContext(self.frame.size) self.layer.render(in:UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return UIImage(cgImage: image!.cgImage!) } } }
sumber
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)); view.backgroundColor = .black; view.layer.cornerRadius = 9; view.asImage();
Anda dapat menggunakan ekstensi
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in:UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: image!.cgImage!) } }
Berikut versi swift 3/4:
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in:UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: image!.cgImage!) } }
sumber
let image = UIImage(view: myView)
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, UIScreen.main.scale)
Ubah UIView Anda menjadi gambar dengan drawViewHierarchyInRect: afterScreenUpdates: yang jauh lebih cepat daripada renderInContext
Catatan penting: jangan panggil fungsi ini dari viewDidLoad atau viewWillAppear , pastikan Anda menangkap tampilan setelah itu ditampilkan / dimuat sepenuhnya
Obj C
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f); [myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO]; UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); myImageView.image = snapshotImageFromMyView;
Simpan album foto gambar yang diedit
UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);
Cepat 3/4
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.isOpaque, 0.0) myView.drawHierarchy(in: myView.bounds, afterScreenUpdates: false) let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() print(snapshotImageFromMyView) myImageView.image = snapshotImageFromMyView
Generalisasi super mudah dengan ekstensi, iOS11, swift3 / 4
extension UIImage{ convenience init(view: UIView) { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) view.drawHierarchy(in: view.bounds, afterScreenUpdates: false) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } } Use : //myView is completly loaded/visible , calling this code after only after viewDidAppear is call imgVV.image = UIImage.init(view: myView) // Simple image object let img = UIImage.init(view: myView)
sumber
Di iOS 10:
extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } }
sumber
Praktik terbaik untuk iOS 10 dan Swift 3
sementara masih mendukung iOS 9 dan sebelumnya masih berfungsi pada iOS 13, Xcode 11.1, Swift 5.1
extension UIView { func asImage() -> UIImage? { if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } else { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0) defer { UIGraphicsEndImageContext() } guard let currentContext = UIGraphicsGetCurrentContext() else { return nil } self.layer.render(in: currentContext) return UIGraphicsGetImageFromCurrentImageContext() } } }
Saya tidak yakin apa maksud pertanyaan itu dengan:
sumber
UIGraphicsBeginImageContext(self.view.bounds.size); self.view.layer.renderInContext(UIGraphicsGetCurrentContext()) var screenShot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
sumber
Misalnya jika saya memiliki view of size: 50 50 pada 100.100. Saya dapat menggunakan yang berikut ini untuk mengambil tangkapan layar:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0); self.view.drawViewHierarchyInRect(CGRectMake(-50,-5-,view.bounds.size.width,view.bounds.size.height), afterScreenUpdates: true) var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();
sumber
Menurut saya, pendekatan dengan penginisialisasi tidak terlalu bagus karena menghasilkan dua gambar.
Saya lebih memilih ini:
extension UIView { var snapshot: UIImage? { UIGraphicsBeginImageContext(self.frame.size) guard let context = UIGraphicsGetCurrentContext() else { return nil } layer.render(in: context) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } }
sumber
Swift 4.2, iOS 10
extension UIView { // If Swift version is lower than 4.2, // You should change the name. (ex. var renderedImage: UIImage?) var image: UIImage? { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } }
Sampel
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) view.backgroundColor = .blue let view2 = UIView(frame: CGRect(x: 10, y: 10, width: 20, height: 20)) view2.backgroundColor = .red view.addSubview(view2) let imageView = UIImageView(image: view.image)
sumber
Ini berfungsi untuk saya untuk Xcode 9 / Swift 3.2 / Swift 4 dan Xcode 8 / Swift 3
if #available(iOS 10.0, *) { // for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson's code let renderer = UIGraphicsImageRenderer(size: view!.bounds.size) let capturedImage = renderer.image { (ctx) in view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true) } return capturedImage } else { // for Xcode 8/Swift 3 UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0) view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false) let capturedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return capturedImage! }
Berikut cara menggunakannya di dalam fungsi:
fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage { guard (view != nil) else{ // if the view is nil (it's happened to me) return an alternative image let errorImage = UIImage(named: "Error Image") return errorImage } // if the view is all good then convert the image inside the view to a uiimage if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(size: view!.bounds.size) let capturedImage = renderer.image { (ctx) in view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: true) } return capturedImage } else { UIGraphicsBeginImageContextWithOptions((view!.bounds.size), view!.isOpaque, 0.0) view!.drawHierarchy(in: view!.bounds, afterScreenUpdates: false) let capturedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return capturedImage! } }
Berikut cara melakukan sesuatu dengan gambar yang dikembalikan dari fungsi:
@IBOutlet weak fileprivate var myCustomView: UIView! var myPic: UIImage? let myImageView = UIImageView() @IBAction fileprivate func saveImageButtonTapped(_ sender: UIButton) { myPic = captureUIImageFromUIView(myCustomView) // display the pic inside a UIImageView myImageView.image = myPic! }
Saya mendapatkan Xcode 9 / Swift 3.2 / Swift 4 dari Paul Hudson, ubah uiview ke uiimage
Saya mendapatkan Xcode 8 / Swift 3 dari suatu tempat di SO sejak lama dan saya lupa di mana :(
sumber
var snapshot = overView.snapshotViewAfterScreenUpdates(false)
atau secara objektif-c
UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];
sumber
Anda dapat menggunakannya dengan mudah dengan menggunakan ekstensi seperti ini
// Take a snapshot from a view (just one view) let viewSnapshot = myView.snapshot // Take a screenshot (with every views in screen) let screenSnapshot = UIApplication.shared.snapshot // Take a snapshot from UIImage initialization UIImage(view: self.view)
Jika Anda ingin menggunakan metode / variabel ekstensi tersebut, terapkan ini
Ekstensi UIImage
extension UIImage { convenience init(view: UIView) { if let cgImage = view.snapshot?.cgImage { self.init(cgImage: cgImage) } else { self.init() } } }
Ekstensi UIView
extension UIView { var snapshot: UIImage? { UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0) if UIGraphicsGetCurrentContext() != nil { drawHierarchy(in: bounds, afterScreenUpdates: true) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } return nil } }
Ekstensi UIApplication
extension UIApplication { var snapshot: UIImage? { return keyWindow?.rootViewController?.view.snapshot } }
sumber
atau iOS 10+ Anda dapat menggunakan UIGraphicsImageRenderer + drawHierarchy baru yang direkomendasikan, yang dalam beberapa situasi bisa jauh lebih cepat daripada layer.renderInContext
extension UIView { func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(size: self.bounds.size) return renderer.image { _ in self.drawHierarchy(in: CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height), afterScreenUpdates: false) } } }
sumber
Terima kasih @Bao Tuan Diep! Saya ingin menambahkan suplemen.
Saat Anda menggunakan kode:
yourView.layer.render(in:UIGraphicsGetCurrentContext()!)
Anda harus memperhatikan bahwa:
- If you had used `autoLayout` or `Masonry` in `yourView` (that you want to convert) . - If you did not add `yourView` to another view which means that `yourView` was not used as a subview but just an object.
Kemudian, Anda harus menggunakan :
untuk memperbarui
yourView
sebelumnyayourView.layer.render(in:UIGraphicsGetCurrentContext()!)
.Jika tidak, Anda mungkin mendapatkan objek gambar yang tidak mengandung elemen
sumber
Swift 4.2.0
import Foundation import UIKit extension UIImage { convenience init(view: UIView) { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) view.drawHierarchy(in: view.bounds, afterScreenUpdates: false) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } }
sumber
Implementasi di Swift 3 :
Tambahkan kode di bawah ini, di luar cakupan kelas.
extension UIImage { convenience init(_ view: UIView) { UIGraphicsBeginImageContext(view.frame.size) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() self.init(cgImage: (image?.cgImage)!) } }
Penggunaan:
let image = UIImage( Your_View_Outlet )
sumber
Saya menerapkan @Naveed J. seperti ini, dan itu bekerja dengan sangat baik.
Inilah perpanjangannya:
Inilah cara saya menerapkannya.
//create an image from yourView to display //determine the frame of the view/imageimage let screen = self.superview!.bounds let width = screen.width / 4 //make image 1/4 width of screen let height = width let frame = CGRect(x: 0, y: 0, width: width, height: height) let x = (screen.size.width - frame.size.width) * 0.5 let y = (screen.size.height - frame.size.height) * 0.5 let mainFrame = CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height) let yourView = YourView() //instantiate yourView yourView.frame = mainFrame //give it the frame yourView.setNeedsDisplay() //tell it to display (I am not 100% sure this is needed) let characterViewImage = yourView.asImage()
sumber
Penginisialisasi dengan UIGraphicsImageRenderer baru tersedia sejak iOS 10:
extension UIImage{ convenience init(view: UIView) { let renderer = UIGraphicsImageRenderer(size: self.bounds.size) let canvas = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height) let image = renderer.image { _ in self.drawHierarchy(in: canvas, afterScreenUpdates: false) } self.init(cgImage: (image?.cgImage)!) } }
sumber
bekerja dengan baik dengan saya!
Swift4
extension UIView { func toImage() -> UIImage { UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0) self.drawHierarchy(in: self.bounds, afterScreenUpdates: false) let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return snapshotImageFromMyView! } }
sumber
return snapshotImageFromMyView!
Utas 1: Kesalahan fatal: Tidak terduga ditemukan nol saat membuka bungkus Nilai opsionalUntuk tampilan berisi subview buram (misalnya, instance UIVisualEffectView ), hanya drawViewHierarchyInRect: afterScreenUpdates yang berfungsi.
Jawaban @ViJay Avhad benar untuk kasus ini.
sumber
Penggunaan UIGraphicsImageRenderer tidak berfungsi saat tampilan berisi sub-tampilan Scene Kit, Metal atau Sprite Kit. Dalam kasus ini, gunakan
let renderer = UIGraphicsImageRenderer(size: view.bounds.size) let image = renderer.image { ctx in view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) }
sumber
please try below code. -(UIImage *)getMainImageFromContext { UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0); [viewBG.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; }
sumber