我的代码在普通设备上运行良好,但在视网膜设备上创建模糊图像。
有人知道我的问题的解决方案吗?
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
从使用
UIGraphicsBeginImageContext
切换到 UIGraphicsBeginImageContextWithOptions
(如本页 所记录)。将 0.0 传递给比例(第三个参数),你将得到一个比例因子等于屏幕比例因子的上下文。
UIGraphicsBeginImageContext
使用固定比例因子 1.0,因此您实际上在 iPhone 4 上获得的图像与在其他 iPhone 上完全相同。我敢打赌,当你隐式地放大它时,iPhone 4 正在应用过滤器,或者只是你的大脑发现它不如周围的一切那么锐利。
所以,我猜:
#import <QuartzCore/QuartzCore.h>
+ (UIImage *)imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
在 Swift 4 中:
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
目前接受的答案现在已经过时了,至少如果你支持 iOS 7.
如果你只支持 iOS7+,这里是你应该使用的:
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0f);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
斯威夫特 4:
func imageWithView(view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
return UIGraphicsGetImageFromCurrentImageContext()
}
根据这篇文章,你可以看到新的iOS7方法
drawViewHierarchyInRect:afterScreenUpdates:
比renderInContext:
快很多倍。
我基于@Dima 解决方案创建了一个 Swift 扩展:
extension UIImage {
class func imageWithView(view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
}
编辑:Swift 4改进版
extension UIImage {
class func imageWithView(_ view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0)
defer { UIGraphicsEndImageContext() }
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
}
用法:
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let image = UIImage.imageWithView(view)
public extension UIView {
@available(iOS 10.0, *)
public func renderToImage(afterScreenUpdates: Bool = false) -> UIImage {
let rendererFormat = UIGraphicsImageRendererFormat.default()
rendererFormat.opaque = isOpaque
let renderer = UIGraphicsImageRenderer(size: bounds.size, format: rendererFormat)
let snapshotImage = renderer.image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
}
return snapshotImage
}
}
要改进@Tommy 和@Dima 的答案,请使用以下类别将 UIView 呈现为 UIImage 具有透明背景 并且不会降低质量。在 iOS7 上工作。 (或者只是在实现中重用该方法,用您的图像替换
self
参考)
#import <UIKit/UIKit.h>
@interface UIView (RenderToImage)
- (UIImage *)imageByRenderingView;
@end
#import "UIView+RenderViewToImage.h"
@implementation UIView (RenderViewToImage)
- (UIImage *)imageByRenderingView
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
@end
具有 UIView 扩展的 Swift 3 解决方案(基于 Dima 的回答)应该是这样的:
extension UIView {
public func getSnapshotImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
let snapshotImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return snapshotImage
}
}
对于 Swift 5.1,您可以使用此扩展:
extension UIView {
func asImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { layer.render(in: $0.cgContext) }
}
}
Drop-in Swift 3.0 扩展,支持新的 iOS 10.0 API 和以前的方法。
注:
!
展开,这可能会导致崩溃。extension UIView
{
public func renderToImage(afterScreenUpdates: Bool = false) -> UIImage?
{
if #available(iOS 10.0, *)
{
let rendererFormat = UIGraphicsImageRendererFormat.default()
rendererFormat.scale = self.layer.contentsScale
rendererFormat.opaque = self.isOpaque
let renderer = UIGraphicsImageRenderer(size: self.bounds.size, format: rendererFormat)
return
renderer.image
{
_ in
self.drawHierarchy(in: self.bounds, afterScreenUpdates: afterScreenUpdates)
}
}
else
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, self.layer.contentsScale)
defer
{
UIGraphicsEndImageContext()
}
self.drawHierarchy(in: self.bounds, afterScreenUpdates: afterScreenUpdates)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
}
斯威夫特 2.0:
使用扩展方法:
extension UIImage{
class func renderUIViewToImage(viewToBeRendered:UIView?) -> UIImage
{
UIGraphicsBeginImageContextWithOptions((viewToBeRendered?.bounds.size)!, false, 0.0)
viewToBeRendered!.drawViewHierarchyInRect(viewToBeRendered!.bounds, afterScreenUpdates: true)
viewToBeRendered!.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}
}
用法:
override func viewDidLoad() {
super.viewDidLoad()
//Sample View To Self.view
let sampleView = UIView(frame: CGRectMake(100,100,200,200))
sampleView.backgroundColor = UIColor(patternImage: UIImage(named: "ic_120x120")!)
self.view.addSubview(sampleView)
//ImageView With Image
let sampleImageView = UIImageView(frame: CGRectMake(100,400,200,200))
//sampleView is rendered to sampleImage
var sampleImage = UIImage.renderUIViewToImage(sampleView)
sampleImageView.image = sampleImage
self.view.addSubview(sampleImageView)
}
extension UIView {
func getSnapshotImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
drawHierarchy(in: bounds, afterScreenUpdates: false)
let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return snapshotImage
}
}
所有 Swift 3 的答案都不适合我,所以我翻译了最被接受的答案:
extension UIImage {
class func imageWithView(view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let img: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
这是基于@Dima 的回答的 Swift 4 UIView 扩展。
extension UIView {
func snapshotImage() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
drawHierarchy(in: bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
是一个相对较新的 API,在 iOS 10 中引入。您可以通过指定点大小 来构造一个 UIGraphicsImageRenderer 。 image 方法接受一个闭包参数并返回一个位图,该位图是执行传递的闭包的结果。在这种情况下,结果是按比例缩小以在指定范围内绘制的原始图像。UIGraphicsImageRenderer
https://nshipster.com/image-resizing/
所以请确保您传递给
UIGraphicsImageRenderer
的尺寸是点,而不是像素。
如果您的图像比您预期的要大,您需要将尺寸除以比例因子。
有时 drawRect 方法会产生问题,所以我得到这些答案更合适。你也可以看看它 捕获 UIView 的 UIImage 卡在 DrawRect 方法中
- (UIImage*)screenshotForView:(UIView *)view
{
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// hack, helps w/ our colors when blurring
NSData *imageData = UIImageJPEGRepresentation(image, 1); // convert to jpeg
image = [UIImage imageWithData:imageData];
return image;
}
最近一定发生了一些变化,因为我无法按照上述所有答案获得视网膜显示图像。
我最后做了什么:
static func takeScreenshot(of viewController: UIViewController) -> UIImage? {
guard let view = viewController.view else {
return nil
}
let scale = UIScreen.main.scale
let size = CGSize(width: view.bounds.size.width * scale, height: view.bounds.size.height * scale)
UIGraphicsBeginImageContextWithOptions(size, view.isOpaque, scale)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
context.scaleBy(x: scale, y: scale) // Set the scale of the graphics context
view.layer.render(in: context)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
return screenshot
}
return nil
}
在此方法中,只需传递一个视图对象,它将返回一个 UIImage 对象。
-(UIImage*)getUIImageFromView:(UIView*)yourView
{
UIGraphicsBeginImageContext(yourView.bounds.size);
[yourView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
将此方法添加到 UIView 类别
- (UIImage*) capture {
UIGraphicsBeginImageContext(self.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}