Преобразование UIImage в форму круга

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

Код, который я использую для создания маски:

  (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef imageNoAlpha = image.CGImage;

    CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();

    CGFloat width = CGImageGetWidth(imageNoAlpha);
    CGFloat height = CGImageGetWidth(imageNoAlpha);

    CGContextRef ctxWithAlpha = CGBitmapContextCreate(nil, width, height, 8, 4*width, cs, kCGImageAlphaPremultipliedFirst);

    CGContextDrawImage(ctxWithAlpha, CGRectMake(0, 0, width, height), imageNoAlpha);

    CGImageRef imageWithAlpha = CGBitmapContextCreateImage(ctxWithAlpha);

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                        CGImageGetHeight(maskRef),
                                        CGImageGetBitsPerComponent(maskRef),
                                        CGImageGetBitsPerPixel(maskRef),
                                        CGImageGetBytesPerRow(maskRef),
                                        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef masked = CGImageCreateWithMask(imageWithAlpha, mask);

    UIImage* retImage= [UIImage imageWithCGImage:masked];
    UIImage* retImageFixed = [retImage transparentBorderImage:1];

    CGImageRelease(mask);
    CGImageRelease(masked);
    CGImageRelease(imageWithAlpha);
    CGContextRelease(ctxWithAlpha);
    CGColorSpaceRelease(cs);

    return retImageFixed;

Заранее спасибо...


person Shahar Nechmad    schedule 13.09.2011    source источник
comment
Может быть. Эти две ссылки могут помочь в том, что вы ищете. 1. stackoverflow.com/questions/4414221/uiimage-in-a-circle 2. stackoverflow.com/questions/1878595/   -  person iOS    schedule 13.09.2011
comment
Спасибо. Я видел много людей, говорящих, что вы можете просто использовать свойство углового радиуса, но это просто неправильно. Хотя это делает угол закругленным, это никогда не делает все изображение похожим на круг.   -  person Shahar Nechmad    schedule 13.09.2011


Ответы (10)


попробуйте этот код

yourImageView.layer.cornerRadius = yourImageView.frame.size.height /2;
yourImageView.layer.masksToBounds = YES;
yourImageView.layer.borderWidth = 0;

это шоу-изображение похоже на круговое изображение ios 7, спасибо

person Waseem Shah    schedule 22.02.2014
comment
К вашему сведению, это решение замедляет прокрутку в табличном представлении. Решение @aToz работает хорошо. - person xiaowl; 09.05.2014
comment
Он отлично работает при прокрутке tableView, я не вижу в этом никаких проблем, мой tableView содержит 246 строк, каждая строка загружает изображение с сервера и все еще отлично работает - person aLFaRSi; 19.07.2014
comment
@aLFaRSi, какое у вас устройство? Плохо работающий код не всегда сразу проявляется. Может быть теоретическое доказательство или эталонный тест обоих методов. - person scord; 18.11.2015
comment
@alFaRSi. Тебе повезло ;) - person Jeff; 27.02.2017
comment
Здесь используется UIImageView, тогда как автор темы запрашивает круг, замаскированный UIImage. - person Mr. Zystem; 31.12.2020

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

например. В моем случае я хочу отобразить изображение на "imageView", поэтому радиус угла в этом случае будет imageView.frame.size.width/2.

- (void)displayImage
{
    imageView.image = [self getRoundedRectImageFromImage:@"Test.png" onReferenceView:imageView withCornerRadius: imageView.frame.size.width/2];
}



- (UIImage *)getRoundedRectImageFromImage :(UIImage *)image onReferenceView :(UIImageView*)imageView withCornerRadius :(float)cornerRadius
{
    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
    [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
                                cornerRadius:cornerRadius] addClip];
    [image drawInRect:imageView.bounds];
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return finalImage;
}
person aToz    schedule 24.01.2014
comment
Третий параметр в UIGraphicsBeginImageContextWithOptions должен быть равен 0,0 вместо 1,0. Потому что 1.0 очень некрасиво рисует - person fnc12; 23.08.2014
comment
@fnc12 спасибо! Мне было интересно, почему результат был размытым и уродливым. - person Chen Li Yong; 02.03.2016

Извините за некрасивое форматирование. Лучшая версия ответа aToz.

@interface UIImage (CircleMask)

+ (UIImage *)roundedRectImageFromImage :(UIImage *)image
                                  size :(CGSize)imageSize
                      withCornerRadius :(float)cornerRadius;

@end

@implementation UIImage(CircleMask)

+(UIImage*)roundedRectImageFromImage:(UIImage *)image
                                size:(CGSize)imageSize
                    withCornerRadius:(float)cornerRadius
{
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);   //  <= notice 0.0 as third scale parameter. It is important cause default draw scale ≠ 1.0. Try 1.0 - it will draw an ugly image..
    CGRect bounds = (CGRect){CGPointZero,imageSize};
    [[UIBezierPath bezierPathWithRoundedRect:bounds
                                cornerRadius:cornerRadius] addClip];
    [image drawInRect:bounds];
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return finalImage;
}

@end

То же самое в Swift:

extension UIImage{

    class func roundedRectImageFromImage(image:UIImage,imageSize:CGSize,cornerRadius:CGFloat)->UIImage{
        UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
        let bounds = CGRect(origin: CGPointZero, size: imageSize)
        UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
        image.drawInRect(bounds)
        let finalImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return finalImage
    }
    
}
person fnc12    schedule 23.08.2014
comment
CGPointZero устарел, вместо этого используйте: CGRect (происхождение: .zero, размер: imageSize). - person grebulon; 13.11.2020

Лучшая версия ответов aToz и fnc12 (в Swift):

extension UIImage
{
    func roundImage() -> UIImage
    {
        let newImage = self.copy() as! UIImage
        let cornerRadius = self.size.height/2
        UIGraphicsBeginImageContextWithOptions(self.size, false, 1.0)
        let bounds = CGRect(origin: CGPointZero, size: self.size)
        UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
        newImage.drawInRect(bounds)
        let finalImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return finalImage
    }
}

Использование:

self.userImageView.image = image.roundedImage()
person Sunkas    schedule 31.08.2015
comment
можем ли мы обрезать и округлить неквадратные изображения? - person khunshan; 08.03.2016

Как насчет получения помощи от UIImageView

+ (UIImage *)circularImage:(UIImage *)image withDiameter:(NSUInteger)diameter
{
    CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.clipsToBounds = YES;
    imageView.image = image;
    CALayer *layer = imageView.layer;


    layer.masksToBounds = YES;

    layer.cornerRadius =MAX( imageView.frame.size.height,imageView.frame.size.width)/2;

    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO, [UIScreen mainScreen].scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [layer renderInContext:context];


    UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return roundedImage;
}
person Max    schedule 13.06.2017

Если вы используете Swift, вы можете импортировать AlamofireImage и использовать одну из его функций. Для обведенного изображения:

let roundImage = UIImage(named: "myImage")!.af_imageRoundedIntoCircle()
person Jovan Stankovic    schedule 16.09.2017

Почувствовал, что должен бросить свою шляпу на ринг. Эффективное и компактное решение Swift 5:

extension UIImage {

    var rounded: UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
        defer { UIGraphicsEndImageContext() }
        let bounds = CGRect(origin: .zero, size: size)
        UIBezierPath(roundedRect: bounds, cornerRadius: size.height/2.0).addClip()
        draw(in: bounds)
        return UIGraphicsGetImageFromCurrentImageContext()
    }

}

person aasatt    schedule 31.01.2020

Если вы используете UIImageView и хотите анимировать размер изображения, сохраняя закругленные углы, вы можете применить преобразование следующим образом:

Цель-C

// Our UIImageView reference
@property (weak, nonatomic) IBOutlet UIImageView *myImageView;

- (void)viewDidLoad {
    [super viewDidLoad];

     myImageView.layer.cornerRadius = myImageView.frame.size.width / 2.0f;
     myImageView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4f, 0.4f);
}

- (void)viewDidAppear:(BOOL)animated {
    [UIView animateWithDuration:1.0 animations:^{
        myImageView.transform = CGAffineTransformIdentity;
    }];
}

Свифт

// Our UIImageView reference
@IBOutlet weak var myImageView:UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()

    myImageView.layer.cornerRadius = myImageView.frame.size.width / 2;
    myImageView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4)
}

override func viewDidAppear(animated: Bool) {
    UIView.animateWithDuration(1.0) {
        myImageView.transform = CGAffineTransformIdentity;
    }
}

ПРИМЕЧАНИЕ. Это также сохранит все AutoLayout constraints.

person RndmTsk    schedule 05.08.2015

Я решаю свою проблему с помощью UIBezierPath

UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:yourImageView.bounds];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = path.CGPath;
yourImageView.layer.mask = maskLayer;
person intermat    schedule 22.03.2016

попробуйте это

UIImageView *circleImageview=[[UIImageView alloc]init];
circleImageview.frame=CGRectMake(0,10, 80, 80)]; 
circleImageview.layer.cornerRadius=circleimagview.frame.size.height/2;
 circleImageview.userInteractionEnabled=YES;
 [self.view addSubview:circleImageview];

Примечание. Убедитесь, что высота и ширина будут такими же, как и в этом представлении.

person shalu chaudhary    schedule 25.01.2018