web-dev-qa-db-ja.com

UIImageの角丸

角の丸い、連絡先アプリの連絡先画像を使用して、iPhoneで画像を描画しようとしています。一般に機能するコードを持っていますが、UIImage描画ルーチン内でEXEC_BAD_ACCESS-KERN_INVALID_ADDRESS。これは cropinging 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;
}

そして、ここにクラッシュログがあります。これらのクラッシュの1つを取得するときは常に同じに見えます

[。 ] 0 com.Apple.CoreGraphics 0x30fe56d8 CGGStateGetRenderingIntent + 4 
 1 libRIP.A.dylib 0x33c4a7d8 ripc_RenderImage + 104 
 2 libRIP.A.dylib 0x33c51868 ripc_DrawImage + 3860 
 3 .CoreGraphics 0x30fecad4 CGContextDelegateDrawImage + 80 
 4 com.Apple.CoreGraphics 0x30feca40 CGContextDrawImage + 368 
 5 UIKit 0x30a6a708-[UIImage drawInRect:blendMode:alpha:] + 1460 
 6 UIKit 0x30a 0x30a [UIImage drawInRect:] + 72 
 7 MyApp 0x0003f8a8-[UIImage(PNAdditions)borderedImageWithRect:radius:](UIImage + PNAdditions.m:187)
57
Jablair

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]];
163
MagicSeth

ここで先に進み、実際にタイトルの質問に答えます。

このカテゴリを試してください。

IImage + additions.h

#import <UIKit/UIKit.h>

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

IImage + 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
25
Jonny

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>
21
cuasijoe

バックグラウンドスレッドでメソッド(borderedImageWithRect)を呼び出している場合、UIGraphics関数はスレッドセーフではないため、クラッシュが発生する可能性があります。このような場合、CGBitmapContextCreate()を使用してコンテキストを作成する必要があります-SDKの「Reflection」サンプルコードを参照してください。

4
fjoachim

私はあなたのクラッシュについての洞察を提供することはできませんが、コーナーを丸くするための別のオプションを提供すると思いました。作業中のアプリケーションで同様の問題が発生しました。コードを書くのではなく、角を隠す別の画像をオーバーレイしています。

4
Lounges

最も簡単な方法は、ビューに無効な[!]丸い長方形の[カスタムではない]ボタンを埋め込み(Interface Builderですべて行うこともできます)、画像をそれに関連付けることです。画像設定メッセージはUIButtonで(UIImageViewと比較して)異なりますが、全体的な見栄えは魅力のように機能します。中央のアイコンが必要な場合はsetImage:forState:を使用し、角のある(連絡先など)画像全体を切りたい場合はsetBackgroundImage:forState:を使用します。もちろん、これらの画像の多くをdrawRectに表示したい場合、これは正しいアプローチではありませんが、埋め込みビューはまさに必要なものです。

3
Max Motovilov

繰り返しますが、 fjoachim's answer :別のスレッドで実行中に描画しようとするときは注意してください。そうしないと、EXC_BAD_ACCESSエラー。

私の回避策は次のようなものでした:

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

(私の場合、UIImageのサイズ変更/スケーリングを行っていました。)

2
PCheese

私は実際に、ニューヨークのiPhone Tech TalkでAppleの誰かと話をする機会がありました。私たちがそれについて話したとき、彼はそれが発行されたスレッドではないと確信していました。 、彼はUIGraphicsBeginImageContextを呼び出すときに生成されたグラフィックコンテキストを保持する必要があると考えました。これは、保持ルールと命名スキームを扱う一般的なルールに違反しているようですが、このフェローは、以前。

おそらく別のスレッドによってメモリが走り書きされている場合、それは私がたまに問題を見るだけだった理由を確かに説明するでしょう。

コードを再検討して修正をテストする時間はありませんでしたが、PCheeseのコメントにより、ここに情報を掲載していないことに気付きました。

...間違って書き留めていない限り、UIGraphicsBeginImageContextCGBitmapContextCreateになっていたはずです...

2
Jablair

時々しかクラッシュしない場合は、クラッシュケースの共通点を把握してください。 dstRectは毎回同じですか?画像のサイズは変わりましたか?

また、CGPathRelease(borderPath)も必要です。ただし、リークが問題を引き起こしているとは思いません。

1
benzado

In 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
}
0
iOS
UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
[self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
0
user3536010