objective-c UIImage 上的圆角

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/205431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 20:50:33  来源:igfitidea点击:

Rounded Corners on UIImage

iphoneobjective-ccocoa-touchimage-manipulation

提问by Jablair

I'm trying to draw images on the iPhone using with rounded corners, a la the contact images in the Contacts app. I've got code that generally work, but it occasionally crashes inside of the UIImage drawing routines with an EXEC_BAD_ACCESS- KERN_INVALID_ADDRESS. I thought this might be related to the cropping questionI asked a few weeks back, but I believe I'm setting up the clipping path correctly.

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

Here's the code I'm using - when it doesn't crash, the result looks fine and anybody looking to get a similar look is free to borrow the code.

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

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

and here's the crash log. It looks the same whenever I get one of these crashes

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

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)

回答by MagicSeth

Here is an even easier method that is available in iPhone 3.0 and up. Every View-based object has an associated layer. Each layer can have a corner radius set, this will give you just what you want:

这是 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]];

回答by Jonny

I'm gonna go ahead here and actually answer the question in the title.

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

Try this category.

试试这个类别。

UIImage+additions.h

UIImage+additions.h

#import <UIKit/UIKit.h>

@interface UIImage (additions)
-(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS;
@end

UIImage+additions.m

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

回答by cuasijoe

If appIconImage is an UIImageView, then:

如果 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];

And also remember:

还要记住:

#import <QuartzCore/QuartzCore.h>

回答by Lounges

I cant offer any insight into your crash, but I thought I would offer another option for rounding the corners. I had a similar problem arise in an application i was working on. Rather than write any code I am overlaying another image which masks off the corners.

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

回答by fjoachim

If you are calling your method (borderedImageWithRect) in a background thread, crashes might occur since UIGraphics-functions are not thread-safe. In such a case, you must create a context using CGBitmapContextCreate() - see the "Reflection" sample code from the SDK.

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

回答by Max Motovilov

The easiest way is to embed a disabled[!] round-rect [not custom!] button in your view (can even do it all in the Interface Builder) and associate your image with it. The image-setting message is different for UIButton (compared to UIImageView), but the overall kludge works like a charm. Use setImage:forState: if you want a centered icon or setBackgroundImage:forState: if you want the whole image with corners cut (like Contacts). Of course if you want to display lots of these images in your drawRect this isn't the right approach, but more likely an embedded view is exactly what you needed anyway...

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

回答by PCheese

I would reiterate fjoachim's answer: be cautious when attempting to draw while running on a separate thread, or you may get EXC_BAD_ACCESSerrors.

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

My workaround went something like this:

我的解决方法是这样的:

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

(In my case I was resizing / scaling UIImages.)

(就我而言,我正在调整/缩放 UIImages。)

回答by Jablair

I actually had a chance to talk about this with somebody from Apple at the iPhone Tech Talk in New York. When we talked about it, he was pretty sure it wasn't a threading issued. Instead, he thought that I needed to retain the graphics context that was generated when calling UIGraphicsBeginImageContext. This seems to violate the general rules dealing with retain rules and naming schemes, but this fellow was pretty sure he'd seen the issue previously.

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

If the memory was getting scribbled, perhaps by another thread, that would certainly explain why I was only seeing the issue occasionally.

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

I haven't had time to revisit the code and test out the fix, but PCheese's comment made me realize I hadn't posted the info here.

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

...unless I wrote that down wrong and UIGraphicsBeginImageContextshould've been CGBitmapContextCreate...

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

回答by benzado

If it only crashes some of the time, figure out what the crash cases have in common. Is dstRect the same every time? Are the images ever a different size?

如果它只是偶尔崩溃,找出崩溃案例的共同点。dstRect 每次都一样吗?图像大小不同吗?

Also, you need to CGPathRelease(borderPath), although I doubt that leak is causing your problem.

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

回答by user3536010

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