it-swarm.com.ru

Скругленные углы на UIImage

Я пытаюсь рисовать изображения на 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) 
 Коды исключений: KERN_INVALID_ADDRESS в 0x6e2e6181 
 Сбой потока: 0 

 Поток 0 Сбой: 
 0 com.Apple.CoreGraphics 0x30fe56GentGentGentGentGentGentGateGTG: __. 1 libRIP.A.dylib 0x33c4a7d8 ripc_RenderImage + 104 
 2 libRIP.A.dylib 0x33c51868 ripc_DrawImage + 3860 
 3 com.Apple.CoreGraphics 0x30fecad4 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

Вот еще более простой метод, который доступен в 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

Я собираюсь пойти дальше и на самом деле ответить на вопрос в названии.

Попробуйте эту категорию.

UIImage + дополнения.h

#import <UIKit/UIKit.h>

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

UIImage + adds.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.

4
fjoachim

Я не могу предложить какое-либо понимание вашего крушения, но я подумал, что предложу другой вариант для скругления углов. У меня была похожая проблема, возникающая в приложении, над которым я работал. Вместо того, чтобы писать какой-либо код, я накладываю другое изображение, которое маскирует углы.

4
Lounges

Самый простой способ - встроить отключенную круглую [!] Кнопку [не пользователь!] В ваше представление (можно даже сделать все это в Интерфейсном Разработчике) и связать ваше изображение с ней. Сообщение установки изображения отличается для UIButton (по сравнению с UIImageView), но общий kludge работает как шарм. Используйте setImage: forState: если вы хотите центрировать значок или setBackgroundImage: forState: если вы хотите, чтобы все изображение было обрезано по углам (например, Контакты). Конечно, если вы хотите отобразить много этих изображений в вашем drawRect, это не правильный подход, но, скорее всего, встроенный вид - это именно то, что вам нужно в любом случае ...

3
Max Motovilov

Я бы повторил ответ fjoachim : будьте осторожны при попытке рисовать во время работы в отдельном потоке, иначе вы можете получить ошибки EXC_BAD_ACCESS.

Мой обходной путь пошел примерно так:

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

(В моем случае я изменял размеры/масштабировал UIImages.)

2
PCheese

У меня действительно была возможность поговорить об этом с кем-то из Apple на iPhone Tech Talk в Нью-Йорке. Когда мы говорили об этом, он был почти уверен, что это не было опубликовано. Вместо этого он подумал, что мне нужно сохранить графический контекст, сгенерированный при вызове UIGraphicsBeginImageContext. Кажется, это нарушает общие правила, относящиеся к правилам сохранения и схемам именования, но этот парень был почти уверен, что видел проблему ранее.

Если память нацарапана, возможно, другим потоком, это наверняка объяснит, почему я видел проблему только изредка.

У меня не было времени пересмотреть код и проверить исправление, но комментарий PCheese заставил меня понять, что я не разместил здесь информацию.

... если я не записал это неправильно и UIGraphicsBeginImageContext не должен был быть CGBitmapContextCreate...

2
Jablair

Если происходит сбой только в течение некоторого времени, выясните, что общего в случаях сбоя. Является ли dstRect одинаковым каждый раз? Изображения когда-либо различаются по размеру?

Кроме того, вам нужно CGPathRelease(borderPath), хотя я сомневаюсь, что утечка вызывает вашу проблему.

1
benzado

В 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