Как преобразовать UIView в изображение
Я хочу преобразовать UIView в изображение и сохранить его в своем приложении. Может кто-нибудь, пожалуйста, скажите мне, как сделать снимок экрана или преобразовать его в изображение и как лучше всего сохранить его в приложении (не в рулоне камеры)? Вот код для представления:
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)
Ответы
Ответ 1
Например, если у меня есть вид размера: 50 50 на 100 100. Я могу использовать следующее, чтобы сделать снимок экрана:
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();
Ответ 2
Расширение на UIView
должно сделать UIView
дело.
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 не рекомендует использовать UIGraphicsBeginImageContext
начиная iOS 10 с введением цветовой гаммы P3. UIGraphicsBeginImageContext
является sRGB и только 32-битным. Они представили новый API UIGraphicsImageRenderer
который полностью управляется цветом, основан на блоках, имеет подклассы для PDF файлов и изображений и автоматически управляет временем жизни контекста. Проверьте сеанс WWDC16 205 для более подробной информации (рендеринг изображения начинается около отметки 11:50)
Edit1: чтобы убедиться, что он работает на каждом устройстве, используйте #available
с #available
к более ранним версиям iOS:
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!)
}
}
}
Ответ 3
вы можете использовать расширение
extension UIImage {
convenience init(view: UIView) {
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in:UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.init(cgImage: image!.cgImage!)
}
}
Здесь быстрая версия 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!)
}
}
Ответ 4
Преобразуйте ваш UIView в изображение с помощью drawViewHierarchyInRect: afterScreenUpdates: который во много раз быстрее, чем renderInContext
Важное примечание: не вызывайте эту функцию из viewDidLoad или viewWillAppear, убедитесь, что вы захватываете представление после того, как оно отображается/загружается полностью
Obj C
UIGraphicsBeginImageContextWithOptions(myView.bounds.size, myView.opaque, 0.0f);
[myView drawViewHierarchyInRect:myView.bounds afterScreenUpdates:NO];
UIImage *snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
myImageView.image = snapshotImageFromMyView;
Сохранить отредактированное изображение Фотоальбом
UIImageWriteToSavedPhotosAlbum(snapshotImageFromMyView, nil,nil, nil);
Свифт 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
Супер легкое обобщение с расширением, 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)
Ответ 5
В 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)!)
}
}
Ответ 6
UIGraphicsBeginImageContext(self.view.bounds.size);
self.view.layer.renderInContext(UIGraphicsGetCurrentContext())
var screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Ответ 7
Лучшая практика с iOS 10 и Swift 3
поддерживая при этом поддержку iOS 9 и более ранних версий
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()
}
}
}
Я не уверен, что вопрос означает:
Каков наилучший способ сохранить его в приложении (не в рулоне камеры)?
Ответ 8
На мой взгляд, подход с инициализатором не так велик, потому что он создает два изображения.
Я предпочитаю это:
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
}
}
Ответ 9
var snapshot = overView.snapshotViewAfterScreenUpdates(false)
или в objective-c
UIView* snapshot = [overView snapshotViewAfterScreenUpdates:NO];
Ответ 10
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) }
}
}
Образец
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)
![enter image description here]()
Ответ 11
Вы можете легко использовать его, используя расширение, подобное этому
// 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)
Если вы хотите использовать этот метод расширения/переменные, выполните это
-
Расширение UIImage
extension UIImage {
convenience init(view: UIView) {
if let cgImage = view.snapshot?.cgImage {
self.init(cgImage: cgImage)
} else {
self.init()
}
}
}
-
Расширение 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
}
}
-
Расширение UIApplication
extension UIApplication {
var snapshot: UIImage? {
return keyWindow?.rootViewController?.view.snapshot
}
}
Ответ 12
Это работает для меня для Xcode 9/Swift 3.2/Swift 4 и Xcode 8/Swift 3
if #available(iOS 10.0, *) {
// for Xcode 9/Swift 3.2/Swift 4 -Paul Hudson 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!
}
Вот как использовать его внутри функции:
fileprivate func captureUIImageFromUIView(_ view:UIView?) -> UIImage {
guard (view != nil) else{
// if the view is nil (it 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!
}
}
Вот как сделать что-то с изображением, возвращаемым из функции:
@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!
}
Я получил ответ Xcode 9/Swift 3.2/Swift 4 от Пола Хадсона, конвертирующий uiview в uiimage
Я получил Xcode 8/Swift 3 откуда-то на SO давным-давно, и я забыл где :(
Ответ 13
или iOS 10+ вы можете использовать новый UIGraphicsImageRenderer + рекомендованный drawHierarchy, который в некоторых ситуациях может быть намного быстрее, чем 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)
}
}
}
Ответ 14
Реализация в Swift 3:
Добавьте код ниже, вне класса.
extension UIImage {
convenience init(_ view: UIView) {
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.init(cgImage: (image?.cgImage)!)
}
}
Использование:
let image = UIImage( Your_View_Outlet )
Ответ 15
Спасибо @Bao Tuan Diep! Я хочу добавить дополнение.
Когда вы используете код:
yourView.layer.render(in:UIGraphicsGetCurrentContext()!)
Вы должны заметить, что:
- 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.
Затем вы должны использовать:
[yourView setNeedsLayout];
[yourView layoutIfNeeded];
обновить yourView
до yourView.layer.render(in:UIGraphicsGetCurrentContext()!)
.
В противном случае вы можете получить объект изображения, который не содержит элементов
Ответ 16
Я применил метод @Naveed J., и он работал как шарм.
Вот его экстентность:
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)
}
}
}
Вот как я его реализовал.
//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()
Ответ 17
Инициализатор с новым UIGraphicsImageRenderer, доступным начиная с 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)!)
}
}
Ответ 18
работать со мной нормально!
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!
}
}
Ответ 19
Для представления содержит размытое подпредставление (например, экземпляр UIVisualEffectView), работает только drawViewHierarchyInRect: afterScreenUpdates.
@ViJay Avhad ответ правильный для этого случая.
Ответ 20
Swift 4.2
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)!)
}
}
с помощью:
let img = UIImage.init(view: self.holderView)
Ответ 21
please try below code.
-(UIImage *)getMainImageFromContext
{
UIGraphicsBeginImageContextWithOptions(viewBG.bounds.size, viewBG.opaque, 0.0);
[viewBG.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}