it-swarm.dev

Abgerundete Ecken auf UIImage

Ich versuche, auf dem iPhone Bilder mit abgerundeten Ecken zu zeichnen, z. B. die Kontaktbilder in der Kontakte-App. Ich habe Code, der im Allgemeinen funktioniert, aber er stürzt gelegentlich in den UIImage-Zeichnungsroutinen mit einem EXEC_BAD_ACCESS - KERN_INVALID_ADDRESS ab. Ich dachte, das könnte mit der Cropping-Frage zusammenhängen Ich habe vor ein paar Wochen gefragt, aber ich glaube, ich stelle den Beschneidungspfad richtig ein.

Hier ist der Code, den ich verwende - wenn er nicht abstürzt, sieht das Ergebnis gut aus und jeder, der nach einem ähnlichen Aussehen sucht, kann sich den Code ausleihen.

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

und hier ist das Absturzprotokoll. Es sieht genauso aus, wenn ich einen dieser Abstürze bekomme

 Ausnahmetyp: EXC_BAD_ACCESS (SIGSEGV) 
 Ausnahmecodes: KERN_INVALID_ADDRESS um 0x6e2e6181 
 Abgestürzter Thread: 0 

 Thread 0 Abgestürzt: 
 __. 1 libRIP.A.dylib 0x33c4a7d8 ripc_RakeImage + 104 
 2 libRIP.A.dylib 0x33c51868 ripc_DrawImage + 3860. _ 368 
 5 UIKit 0x30a6a708 - [UIImage drawInRect: blendMode: alpha:] + 1460 
 6 UIKit 0x30a66904 - [UIImage drawInRect:] + 72 
 7 MyApp 0x0003f8a8 - [UIImage (PNAdditions) (UIImage + PNAdditions.m: 187) 
57
Jablair

Hier ist eine noch einfachere Methode, die in iPhone 3.0 und höher verfügbar ist. Jedem View-basierten Objekt ist ein Layer zugeordnet. Für jede Ebene kann ein Eckenradius festgelegt werden. Dadurch erhalten Sie genau das, was Sie möchten:

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

Ich werde hier weitermachen und eigentlich die Frage im Titel beantworten.

Versuchen Sie diese Kategorie.

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

Wenn appIconImage eine UIImageView ist, dann gilt Folgendes:

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

Und denk dran: 

#import <QuartzCore/QuartzCore.h>
21
cuasijoe

Wenn Sie Ihre Methode (borderedImageWithRect) in einem Hintergrundthread aufrufen, können Abstürze auftreten, da UIGraphics-Funktionen nicht threadsicher sind. In diesem Fall müssen Sie einen Kontext mit CGBitmapContextCreate () erstellen. Weitere Informationen finden Sie im Beispielcode "Reflection" aus dem SDK.

4
fjoachim

Ich kann Ihnen keinen Einblick in Ihren Absturz geben, aber ich dachte, ich würde eine weitere Option zum Abrunden der Ecken anbieten. Ich hatte ein ähnliches Problem in einer Anwendung, an der ich arbeitete. Anstatt irgendeinen Code zu schreiben, füge ich ein anderes Bild ein, das die Ecken abblendet.

4
Lounges

Am einfachsten ist es, eine deaktivierte Schaltfläche [!] Round-rect [nicht benutzerdefiniert!] In Ihre Ansicht einzubetten (dies kann sogar im Interface Builder ausgeführt werden) und Ihr Bild damit zu verknüpfen. Die Bildeinstellungsnachricht unterscheidet sich für UIButton (im Vergleich zu UIImageView), aber der allgemeine Effekt wirkt wie ein Zauber. Verwenden Sie setImage: forState: wenn Sie ein zentriertes Symbol oder setBackgroundImage: forState: möchten, wenn das gesamte Bild mit Ecken geschnitten werden soll (z. B. Kontakte). Wenn Sie viele dieser Bilder in drawRect anzeigen möchten, ist dies natürlich nicht der richtige Ansatz, aber wahrscheinlicher ist eine eingebettete Ansicht sowieso genau das, was Sie brauchen ...

3
Max Motovilov

fjoachim's answer : Seien Sie vorsichtig, wenn Sie versuchen, zu zeichnen, während Sie einen separaten Thread ausführen. Andernfalls erhalten Sie EXC_BAD_ACCESS-Fehler.

Meine Problemumgehung lief etwa so ab:

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

(In meinem Fall habe ich UIImages skaliert/skaliert.)

2
PCheese

Beim iPhone Tech Talk in New York hatte ich tatsächlich Gelegenheit, mit jemandem von Apple darüber zu sprechen. Als wir darüber sprachen, war er ziemlich sicher, dass es kein Threading war. Stattdessen dachte er, ich müsse den Grafikkontext beibehalten, der beim Aufruf von UIGraphicsBeginImageContext generiert wurde. Dies scheint gegen die allgemeinen Regeln zu verstoßen, die sich auf die Aufbewahrungsregeln und Namensschemata beziehen, aber dieser Bursche war sich ziemlich sicher, dass er das Problem zuvor gesehen hatte.

Wenn die Erinnerung gekratzt wurde, vielleicht von einem anderen Thread, würde das sicherlich erklären, warum ich das Problem nur gelegentlich sah.

Ich hatte keine Zeit, den Code erneut zu überdenken und den Fix zu testen, aber PCheeses Kommentar ließ mich erkennen, dass ich die Informationen hier nicht gepostet hatte.

... wenn ich das nicht falsch geschrieben habe und UIGraphicsBeginImageContext hätte CGBitmapContextCreate...

2
Jablair

Wenn es nur zeitweise abstürzt, sollten Sie herausfinden, was die Absturzfälle gemeinsam haben. Ist dstRect jedes Mal gleich? Sind die Bilder immer eine andere Größe?

Sie müssen auch CGPathRelease(borderPath), obwohl ich bezweifle, dass ein Leck Ihr Problem verursacht.

1
benzado

In Swift 4.2 und 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