代码之家  ›  专栏  ›  技术社区  ›  catlan

UIImage圆角

  •  70
  • catlan  · 技术社区  · 16 年前

    我试图在UIImage上获得圆角,到目前为止,我读到的最简单的方法是使用掩码图像。为此,我使用了TheElements iPhone示例中的代码和我找到的一些图像调整代码。我的问题是,resizedImage总是空的,我找不到错误。..

    - (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize
    {
        CGSize imageSize = [self size];
        float width = imageSize.width;
        float height = imageSize.height;
    
        // scaleFactor will be the fraction that we'll
        // use to adjust the size. For example, if we shrink
        // an image by half, scaleFactor will be 0.5. the
        // scaledWidth and scaledHeight will be the original,
        // multiplied by the scaleFactor.
        //
        // IMPORTANT: the "targetHeight" is the size of the space
        // we're drawing into. The "scaledHeight" is the height that
        // the image actually is drawn at, once we take into
        // account the ideal of maintaining proportions
    
        float scaleFactor = 0.0; 
        float scaledWidth = targetSize.width;
        float scaledHeight = targetSize.height;
    
        CGPoint thumbnailPoint = CGPointMake(0,0);
    
        // since not all images are square, we want to scale
        // proportionately. To do this, we find the longest
        // edge and use that as a guide.
    
        if ( CGSizeEqualToSize(imageSize, targetSize) == NO )
        { 
            // use the longeset edge as a guide. if the
            // image is wider than tall, we'll figure out
            // the scale factor by dividing it by the
            // intended width. Otherwise, we'll use the
            // height.
    
            float widthFactor = targetSize.width / width;
            float heightFactor = targetSize.height / height;
    
            if ( widthFactor < heightFactor )
                scaleFactor = widthFactor;
            else
                scaleFactor = heightFactor;
    
            // ex: 500 * 0.5 = 250 (newWidth)
    
            scaledWidth = width * scaleFactor;
            scaledHeight = height * scaleFactor;
    
            // center the thumbnail in the frame. if
            // wider than tall, we need to adjust the
            // vertical drawing point (y axis)
    
            if ( widthFactor < heightFactor )
                thumbnailPoint.y = (targetSize.height - scaledHeight) * 0.5;
    
            else if ( widthFactor > heightFactor )
                thumbnailPoint.x = (targetSize.width - scaledWidth) * 0.5;
        }
    
    
        CGContextRef mainViewContentContext;
        CGColorSpaceRef colorSpace;
    
        colorSpace = CGColorSpaceCreateDeviceRGB();
    
        // create a bitmap graphics context the size of the image
        mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    
        // free the rgb colorspace
        CGColorSpaceRelease(colorSpace);    
    
        if (mainViewContentContext==NULL)
            return NULL;
    
        //CGContextSetFillColorWithColor(mainViewContentContext, [[UIColor whiteColor] CGColor]);
        //CGContextFillRect(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height));
    
        CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage);
    
        // Create CGImageRef of the main view bitmap content, and then
        // release that bitmap context
        CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext);
        CGContextRelease(mainViewContentContext);
    
        CGImageRef maskImage = [[UIImage imageNamed:@"Mask.png"] CGImage];
    
        CGImageRef resizedImage = CGImageCreateWithMask(mainViewContentBitmapContext, maskImage);
        CGImageRelease(mainViewContentBitmapContext);
    
        // convert the finished resized image to a UIImage 
        UIImage *theImage = [UIImage imageWithCGImage:resizedImage];
    
        // image is retained by the property setting above, so we can 
        // release the original
        CGImageRelease(resizedImage);
    
        // return the image
        return theImage;
    }
    
    16 回复  |  直到 16 年前
        1
  •  203
  •   jessecurry    15 年前

    如果您使用UIImageView显示图像,只需执行以下操作:

    imageView.layer.cornerRadius = 5.0;
    imageView.layer.masksToBounds = YES;
    

    要添加边框:

    imageView.layer.borderColor = [UIColor lightGrayColor].CGColor;
    imageView.layer.borderWidth = 1.0;
    

    我相信你必须进口 <QuartzCore/QuartzCore.h> 并链接到上面的代码以使其工作。

        2
  •  84
  •   epatel    13 年前

    这些线怎么样。..

    // Get your image somehow
    UIImage *image = [UIImage imageNamed:@"image.jpg"];
    
    // Begin a new image that will be the new image with the rounded corners 
    // (here with the size of an UIImageView)
    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
    
    // Add a clip before drawing anything, in the shape of an rounded rect
    [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds 
                                cornerRadius:10.0] addClip];
    // Draw your image
    [image drawInRect:imageView.bounds];
    
    // Get the image, here setting the UIImageView image
    imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    
    // Lets forget about that we were drawing
    UIGraphicsEndImageContext();
    
        3
  •  27
  •   Besi    10 年前

    我创造了一个 UIImage -swift中的扩展,基于@epatel的精彩回答:

    extension UIImage{
        var roundedImage: UIImage {
            let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size)
            UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
            defer { 
                // End context after returning to avoid memory leak
                UIGraphicsEndImageContext() 
            }
           
            UIBezierPath(
                roundedRect: rect,
                cornerRadius: self.size.height
                ).addClip()
            self.drawInRect(rect)
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
    

    在故事板中测试:

    storyboard

        4
  •  14
  •   catlan    16 年前

    问题是CGImageCreateWithMask的使用返回了全黑图像。我找到的解决方案是使用CGContextClipToMask:

    CGContextRef mainViewContentContext;
    CGColorSpaceRef colorSpace;
    
    colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // create a bitmap graphics context the size of the image
    mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    
    // free the rgb colorspace
    CGColorSpaceRelease(colorSpace);    
    
    if (mainViewContentContext==NULL)
        return NULL;
    
    CGImageRef maskImage = [[UIImage imageNamed:@"mask.png"] CGImage];
    CGContextClipToMask(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height), maskImage);
    CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage);
    
    
    // Create CGImageRef of the main view bitmap content, and then
    // release that bitmap context
    CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext);
    CGContextRelease(mainViewContentContext);
    
    // convert the finished resized image to a UIImage 
    UIImage *theImage = [UIImage imageWithCGImage:mainViewContentBitmapContext];
    // image is retained by the property setting above, so we can 
    // release the original
    CGImageRelease(mainViewContentBitmapContext);
    
    // return the image
    return theImage;
    
        5
  •  5
  •   wisequark    16 年前

    延伸 Besi's excellent answer ,使用正确的比例,in Swift 4 :

    extension UIImage {
    
        public func rounded(radius: CGFloat) -> UIImage {
            let rect = CGRect(origin: .zero, size: size)
            UIGraphicsBeginImageContextWithOptions(size, false, 0)
            UIBezierPath(roundedRect: rect, cornerRadius: radius).addClip()
            draw(in: rect)
            return UIGraphicsGetImageFromCurrentImageContext()!
        }
    
    }
    
        6
  •  4
  •   Voda Ion    12 年前

    你实际上除了在那里扩展之外什么也没做。您需要做的是通过使用CGPath剪切图像来“掩盖”图像的角。例如-

     - (void)drawRect:(CGRect)rect {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextBeginTransparencyLayerWithRect(context, self.frame, NULL);
        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);  
        CGFloat roundRadius = (radius) ? radius : 12.0;
        CGFloat minx = CGRectGetMinX(self.frame), midx = CGRectGetMidX(self.frame), maxx = CGRectGetMaxX(self.frame);
        CGFloat miny = CGRectGetMinY(self.frame), midy = CGRectGetMidY(self.frame), maxy = CGRectGetMaxY(self.frame);
    
        // draw the arcs, handle paths
        CGContextMoveToPoint(context, minx, midy);
        CGContextAddArcToPoint(context, minx, miny, midx, miny, roundRadius);
        CGContextAddArcToPoint(context, maxx, miny, maxx, midy, roundRadius);
        CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, roundRadius);
        CGContextAddArcToPoint(context, minx, maxy, minx, midy, roundRadius);
        CGContextClosePath(context);
        CGContextDrawPath(context, kCGPathFill);
        CGContextEndTransparencyLayer(context);
    }
    

    我建议查看Quartz 2D编程指南或其他一些示例。

        7
  •  2
  •   Augustine P A    12 年前
    static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)
    {
      float fw, fh;
      if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
      }
      CGContextSaveGState(context);
      CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
      CGContextScaleCTM (context, ovalWidth, ovalHeight);
      fw = CGRectGetWidth (rect) / ovalWidth;
      fh = CGRectGetHeight (rect) / ovalHeight;
      CGContextMoveToPoint(context, fw, fh/2);
      CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
      CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
      CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
      CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
      CGContextClosePath(context);
      CGContextRestoreGState(context);
    }
    
    + (UIImage *)imageWithRoundCorner:(UIImage*)img andCornerSize:(CGSize)size
    {
        UIImage * newImage = nil;
    
        if( nil != img)
        {
           @autoreleasepool {
            int w = img.size.width;
            int h = img.size.height;
    
            CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
    
            CGContextBeginPath(context);
            CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
            addRoundedRectToPath(context, rect, size.width, size.height);
            CGContextClosePath(context);
            CGContextClip(context);
    
            CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
    
            CGImageRef imageMasked = CGBitmapContextCreateImage(context);
            CGContextRelease(context);
            CGColorSpaceRelease(colorSpace);
            [img release];
    
            newImage = [[UIImage imageWithCGImage:imageMasked] retain];
            CGImageRelease(imageMasked);
    
           }
        }
    
      return newImage;
    }
    
        8
  •  1
  •   sang    15 年前

    我认为这可能非常相关: 在iOS 11中,有一种非常方便的方法来舍入(图像)视图的每个角。

    let imageView = UIImageView(image: UIImage(named: "myImage"))    
    imageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
    imageView.layer.cornerRadius = 10.0
    
        9
  •  1
  •   bartosss    8 年前

    我喜欢@samwize的答案,但当与collectionView一起使用时,它会导致我严重的内存泄漏。 为了解决这个问题,我发现 UIGraphicsEndImageContext() 不见了

    extension UIImage {
        /**
         Rounds corners of UIImage
         - Parameter proportion: Proportion to minimum paramter (width or height)
                                 in order to have the same look of corner radius independetly
                                 from aspect ratio and actual size
         */
        func roundCorners(proportion: CGFloat) -> UIImage {
            let minValue = min(self.size.width, self.size.height)
            let radius = minValue/proportion
            
            let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: self.size)
            UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
            UIBezierPath(roundedRect: rect, cornerRadius: radius).addClip()
            self.draw(in: rect)
            let image = UIGraphicsGetImageFromCurrentImageContext() ?? self
            UIGraphicsEndImageContext()
            return image
        }
    }
    

    请随意通过半径而不是比例。 proportion 使用它是因为我有收藏视图滚动,图像大小不同,因此使用常量时 半径 它实际上在属性方面看起来不同(例如:两个图像,一个是1000x1000,另一个是2000x2000, 拐角半径 30的每一个看起来都不一样)

    所以如果你这样做 image.roundCorners(proportion: 20) 所有的图片看起来都有相同的角半径。

    这个答案也是一个更新版本。

        10
  •  1
  •   Idan    8 年前

    它与剪裁而不是遮罩一起工作的原因似乎是颜色空间。

    苹果文档如下。

    面具 一个面具。如果掩码是图像,则它必须在DeviceGray颜色空间中,不能有alpha分量,并且本身不能被图像掩码或掩码颜色掩码。如果遮罩与图像参数指定的图像大小不同,则Quartz会缩放遮罩以适应图像。

        11
  •  1
  •   samwize    7 年前

    大家好,试试这段代码,

    + (UIImage *)roundedRectImageFromImage:(UIImage *)image withRadious:(CGFloat)radious {
    
    if(radious == 0.0f)
        return image;
    
    if( image != nil) {
    
        CGFloat imageWidth = image.size.width;
        CGFloat imageHeight = image.size.height;
    
        CGRect rect = CGRectMake(0.0f, 0.0f, imageWidth, imageHeight);
        UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
        const CGFloat scale = window.screen.scale;
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
    
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        CGContextBeginPath(context);
        CGContextSaveGState(context);
        CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
        CGContextScaleCTM (context, radious, radious);
    
        CGFloat rectWidth = CGRectGetWidth (rect)/radious;
        CGFloat rectHeight = CGRectGetHeight (rect)/radious;
    
        CGContextMoveToPoint(context, rectWidth, rectHeight/2.0f);
        CGContextAddArcToPoint(context, rectWidth, rectHeight, rectWidth/2.0f, rectHeight, radious);
        CGContextAddArcToPoint(context, 0.0f, rectHeight, 0.0f, rectHeight/2.0f, radious);
        CGContextAddArcToPoint(context, 0.0f, 0.0f, rectWidth/2.0f, 0.0f, radious);
        CGContextAddArcToPoint(context, rectWidth, 0.0f, rectWidth, rectHeight/2.0f, radious);
        CGContextRestoreGState(context);
        CGContextClosePath(context);
        CGContextClip(context);
    
        [image drawInRect:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)];
    
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
    return nil;
    }
    

    干杯!!!

        12
  •  0
  •   Community CDub    8 年前

    当你使用图像尺寸时,很容易创建一个圆形的图像。

    cell.messageImage.layer.cornerRadius = image.size.width / 2
    cell.messageImage.layer.masksToBounds = true
    
        13
  •  0
  •   user3182143    8 年前

    找到最好和简单的方法如下(没有答案):

    UIImageView *imageView;
    
    imageView.layer.cornerRadius = imageView.frame.size.width/2.0f;
    imageView.layer.masksToBounds = TRUE;
    

    很简单,做得对。

        14
  •  0
  •   sjaustirni Keyki    7 年前

    See here... IMO,除非你绝对需要用代码来做,否则只需在上面叠加一个图像。

    一些沿着线的东西。..

    - (void)drawRect:(CGRect)rect 
    {
        // Drawing code
        [backgroundImage drawInRect:rect];
        [buttonOverlay drawInRect:rect];    
    }
    
        15
  •  0
  •   scrat84    6 年前

    为了创建圆角图像,我们可以使用quartzcore。

    如何添加QuartzCore框架?

    Click  project -Targets
        ->project
           ->BuildPhase
               ->Link Binary with Libraries
                 ->Then click + symbol finally select from list and add it
    

    或者

    Click  project -Targets
        ->Targets
          ->general
            ->Linked Frameworks and Libraries
              ->Then click + symbol finally select from list and add the QuartzCore framework
    

    现在导入

    #import <QuartzCore/QuartzCore.h> 
    

    在ViewController中

    然后在viewDidLoad方法中

    self.yourImageView.layer.cornerRadius = 5.0;
    self.yourImageView.layer.borderWidth = 1.0f;
    self.yourImageView.layer.borderColor = [UIColor blackColor].CGColor;
    self.yourImageView.layer.masksToBounds = YES;