我正在尝试使用圆角在iPhone上绘制图像,以及“联系人”应用中的联系人图像。我有一些通常有效的代码,但它偶尔会在UIImage绘图例程中使用EXEC_BAD_ACCESS
- KERN_INVALID_ADDRESS
崩溃。我认为这可能与几个星期前我问的cropping question有关,但我相信我正确设置了剪切路径。
这是我正在使用的代码 - 当它没有崩溃时,结果看起来很好,任何想要获得类似外观的人都可以免费借用代码。
- (UIImage *)borderedImageWithRect: (CGRect)dstRect radius:(CGFloat)radius {
UIImage *maskedImage = nil;
radius = MIN(radius, .5 * MIN(CGRectGetWidth(dstRect), CGRectGetHeight(dstRect)));
CGRect interiorRect = CGRectInset(dstRect, radius, radius);
UIGraphicsBeginImageContext(dstRect.size);
CGContextRef maskedContextRef = UIGraphicsGetCurrentContext();
CGContextSaveGState(maskedContextRef);
CGMutablePathRef borderPath = CGPathCreateMutable();
CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(180), PNDegreeToRadian(270), NO);
CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(270.0), PNDegreeToRadian(360.0), NO);
CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(0.0), PNDegreeToRadian(90.0), NO);
CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(90.0), PNDegreeToRadian(180.0), NO);
CGContextBeginPath(maskedContextRef);
CGContextAddPath(maskedContextRef, borderPath);
CGContextClosePath(maskedContextRef);
CGContextClip(maskedContextRef);
[self drawInRect: dstRect];
maskedImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(maskedContextRef);
UIGraphicsEndImageContext();
return maskedImage;
}
这是崩溃日志。每当我遇到其中一次崩溃时,它看起来都是一样的
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x6e2e6181 Crashed Thread: 0 Thread 0 Crashed: 0 com.apple.CoreGraphics 0x30fe56d8 CGGStateGetRenderingIntent + 4 1 libRIP.A.dylib 0x33c4a7d8 ripc_RenderImage + 104 2 libRIP.A.dylib 0x33c51868 ripc_DrawImage + 3860 3 com.apple.CoreGraphics 0x30fecad4 CGContextDelegateDrawImage + 80 4 com.apple.CoreGraphics 0x30feca40 CGContextDrawImage + 368 5 UIKit 0x30a6a708 -[UIImage drawInRect:blendMode:alpha:] + 1460 6 UIKit 0x30a66904 -[UIImage drawInRect:] + 72 7 MyApp 0x0003f8a8 -[UIImage(PNAdditions) borderedImageWithRect:radius:] (UIImage+PNAdditions.m:187)
答案 0 :(得分:163)
这是iPhone 3.0及更高版本中提供的更简单的方法。每个基于视图的对象都有一个关联的图层。每个图层都可以设置一个圆角半径,这将为您提供所需的内容:
UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * l = [roundedView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:10.0];
// You can even add a border
[l setBorderWidth:4.0];
[l setBorderColor:[[UIColor blueColor] CGColor]];
答案 1 :(得分:25)
我要继续在这里实际回答标题中的问题。
尝试此类别。
<强>的UIImage + additions.h 强>
#import <UIKit/UIKit.h>
@interface UIImage (additions)
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS;
@end
<强>的UIImage + additions.m 强>
#import "UIImage+additions.h"
@implementation UIImage (additions)
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS {
UIImage *image = self;
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
const CGRect RECT = CGRectMake(0, 0, image.size.width, image.size.height);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:RECT cornerRadius:RADIUS] addClip];
// Draw your image
[image drawInRect:RECT];
// Get the image, here setting the UIImageView image
//imageView.image
UIImage* imageNew = UIGraphicsGetImageFromCurrentImageContext();
// Lets forget about that we were drawing
UIGraphicsEndImageContext();
return imageNew;
}
@end
答案 2 :(得分:21)
如果appIconImage是UIImageView,那么:
appIconImage.image = [UIImage imageWithContentsOfFile:@"image.png"];
appIconImage.layer.masksToBounds = YES;
appIconImage.layer.cornerRadius = 10.0;
appIconImage.layer.borderWidth = 1.0;
appIconImage.layer.borderColor = [[UIColor grayColor] CGColor];
还要记住:
#import <QuartzCore/QuartzCore.h>
答案 3 :(得分:4)
我无法提供任何关于你的崩溃的见解,但我想我会提供另一种选择来绕过角落。我正在处理的应用程序中出现了类似的问题。我没有写任何代码,而是覆盖另一个掩盖角落的图像。
答案 4 :(得分:4)
如果在后台线程中调用方法(borderedImageWithRect),则可能会发生崩溃,因为UIGraphics函数不是线程安全的。在这种情况下,您必须使用CGBitmapContextCreate()创建上下文 - 请参阅SDK中的“反射”示例代码。
答案 5 :(得分:3)
最简单的方法是在视图中嵌入一个禁用的[!] round-rect [not custom!]按钮(甚至可以在Interface Builder中完成所有操作),并将图像与之关联起来。 UIButton的图像设置信息不同(与UIImageView相比),但整体的kludge就像一个魅力。使用setImage:forState:如果你想要一个居中的图标或setBackgroundImage:forState:如果你想要整个图像切角(比如Contacts)。当然,如果你想在drawRect中显示很多这些图像,这不是正确的方法,但更有可能的是嵌入式视图正是你所需要的......
答案 6 :(得分:2)
我会重申fjoachim's answer:在单独的线程上运行时尝试绘制时要小心,否则可能会出现EXC_BAD_ACCESS
错误。
我的解决方法是这样的:
UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"]
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
(在我的情况下,我正在调整/缩放UIImages。)
答案 7 :(得分:2)
我实际上有机会在纽约的iPhone Tech Talk上与Apple的某个人谈论这件事。当我们谈到它时,他很确定它不是一个线程。相反,他认为我需要保留调用UIGraphicsBeginImageContext
时生成的图形上下文。这似乎违反了关于保留规则和命名方案的一般规则,但这个人很确定他以前见过这个问题。
如果内存被潦草地写下来,也许是另一个帖子,那肯定会解释为什么我偶尔会看到这个问题。
我没有时间重新访问代码并测试修复,但是PCheese的评论让我意识到我没有在这里发布信息。
......除非我写错了,UIGraphicsBeginImageContext
应该CGBitmapContextCreate
...
答案 8 :(得分:1)
如果它只在某些时候崩溃,请找出崩溃案例的共同点。 dstRect每次都一样吗?图像的大小是不同的吗?
此外,您需要CGPathRelease(borderPath)
,但我怀疑泄漏是否会导致您的问题。
答案 9 :(得分:0)
UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"]
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
答案 10 :(得分:0)
在Swift 4.2和Xcode 10.1中
let imgView = UIImageView()
imgView.frame = CGRect(x: 200, y: 200, width: 200, height: 200)
imgView.image = UIImage(named: "yourimagename")
imgView.imgViewCorners()
//If you want complete round shape
//imgView.imgViewCorners(width: imgView.frame.width)//Pass ImageView width
view.addSubview(imgView)
extension UIImageView {
//If you want only round corners
func imgViewCorners() {
layer.cornerRadius = 10
layer.borderWidth = 1.0
layer.borderColor = UIColor.red.cgColor
layer.masksToBounds = true
}
//If you want complete round shape
func imgViewCorners(width:CGFloat) {
layer.cornerRadius = width/2
layer.borderWidth = 1.0
layer.borderColor = UIColor.red.cgColor
layer.masksToBounds = true
}
答案 11 :(得分:-1)
在xib或storyboard中设置图像(图像宽度和高度41x41)。
FirstViewController.h
@interface....
IBOutlet UIImageView *testImg;
@end
FirstViewController.m
-(void)viewDidLoad{
testImg.layer.backgroundColor=[[UIColor clearColor] CGColor];
testImg.layer.cornerRadius=20;
testImg.layer.masksToBounds = YES;
}