60

我正在尝试使用圆角在 iPhone 上绘制图像,例如联系人应用程序中的联系人图像。我有通常可以工作的代码,但它偶尔会在 UIImage 绘图例程中崩溃,并带有EXEC_BAD_ACCESS- KERN_INVALID_ADDRESS。我认为这可能与我几周前提出的裁剪问题有关,但我相信我正确设置了裁剪路径。

这是我正在使用的代码——当它没有崩溃时,结果看起来很好,任何想要获得类似外观的人都可以免费借用代码。

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

这是崩溃日志。每当我遇到这些崩溃之一时,它看起来都一样

异常类型:EXC_BAD_ACCESS (SIGSEGV)
异常代码:0x6e2e6181 处的 KERN_INVALID_ADDRESS
崩溃的线程:0

线程 0 崩溃:
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)
4

12 回答 12

165

这是在 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]];
于 2009-08-20T17:33:08.700 回答
27

我将继续在这里并实际回答标题中的问题。

试试这个类别。

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
于 2013-09-03T06:56:36.827 回答
22

如果 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>
于 2009-09-22T20:14:52.707 回答
4

我无法对您的崩溃提供任何见解,但我想我会提供另一种选择来解决问题。我正在处理的应用程序中出现了类似的问题。我没有编写任何代码,而是覆盖了另一个掩盖角落的图像。

于 2008-10-15T17:28:41.907 回答
4

如果您在后台线程中调用您的方法 (borderedImageWithRect),则可能会发生崩溃,因为 UIGraphics 函数不是线程安全的。在这种情况下,您必须使用 CGBitmapContextCreate() 创建上下文 - 请参阅 SDK 中的“反射”示例代码。

于 2009-01-17T01:38:00.553 回答
3

最简单的方法是在您的视图中嵌入一个 disabled[!] 圆形 [not custom!] 按钮(甚至可以在 Interface Builder 中完成所有操作)并将您的图像与之关联。UIButton 的图像设置消息不同(与 UIImageView 相比),但整体 kludge 就像一个魅力。使用 setImage:forState: 如果你想要一个居中的图标或 setBackgroundImage:forState: 如果你想要切角的整个图像(如联系人)。当然,如果您想在 drawRect 中显示大量这些图像,这不是正确的方法,但更可能的是嵌入式视图正是您所需要的......

于 2008-12-17T00:47:16.613 回答
2

我要重申fjoachim 的回答:在单独的线程上运行时尝试绘制时要小心,否则可能会EXC_BAD_ACCESS出错。

我的解决方法是这样的:

UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];

(在我的情况下,我正在调整 UIImages 的大小/缩放。)

于 2009-02-04T05:57:15.100 回答
2

实际上,我有机会在纽约举行的 iPhone 技术讲座上与 Apple 的某个人谈论这个问题。当我们谈论它时,他很确定这不是线程发布的。相反,他认为我需要保留调用UIGraphicsBeginImageContext. 这似乎违反了处理保留规则和命名方案的一般规则,但是这家伙很确定他以前见过这个问题。

如果内存被乱写,也许是另一个线程,那肯定可以解释为什么我只是偶尔看到这个问题。

我没有时间重新查看代码并测试修复,但 PCheese 的评论让我意识到我没有在这里发布信息。

...除非我写错了并且UIGraphicsBeginImageContext应该是CGBitmapContextCreate...

于 2009-02-04T10:10:58.350 回答
1

如果它只是在某些时候崩溃,请找出崩溃案例的共同点。dstRect 每次都一样吗?图像的大小是否不同?

此外,您需要CGPathRelease(borderPath),尽管我怀疑泄漏会导致您的问题。

于 2008-10-15T19:07:13.157 回答
0
UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
于 2015-02-04T09:20:14.677 回答
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
}
于 2019-02-01T09:47:18.627 回答
-1

在 xib 或情节提要中设置图像(图像宽度和高度 41x41)。

第一视图控制器.h

@interface....

IBOutlet UIImageView *testImg;

@end

第一视图控制器.m

-(void)viewDidLoad{
        testImg.layer.backgroundColor=[[UIColor clearColor] CGColor];
        testImg.layer.cornerRadius=20;
        testImg.layer.masksToBounds = YES;
    }
于 2014-06-25T09:27:44.440 回答