Закругленные углы на 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;
}


и вот краш лог. Это выглядит так же, когда я получаю один из этих сбоев




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)
613   11  

11 ответов:

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

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

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

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

#import <UIKit/UIKit.h>

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

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

#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

Если 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>

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

Если вы вызываете свой метод (borderedImageWithRect) в фоновом потоке, могут произойти сбои, так как UIGraphics-функции не являются потокобезопасными. В таком случае необходимо создать контекст с помощью CGBitmapContextCreate() - см. Пример кода "Отражение" из пакета SDK.

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

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

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

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

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

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

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

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

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

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

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

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

установите изображение в xib или раскадровке (ширина и высота изображения 41x41).

FirstViewController.h

@interface....

IBOutlet UIImageView *testImg;

@end

FirstViewController.м

-(void)viewDidLoad{
        testImg.layer.backgroundColor=[[UIColor clearColor] CGColor];
        testImg.layer.cornerRadius=20;
        testImg.layer.masksToBounds = YES;
    }

Comments

    Ничего не найдено.