【问题标题】:UIImage rounded cornersUIImage圆角
【发布时间】:2010-09-20 16:50:03
【问题描述】:

我尝试在 UIImage 上获得圆角,到目前为止我读到的,最简单的方法是使用蒙版图像。为此,我使用了 TheElements iPhone Example 中的代码和我找到的一些图像大小调整代码。我的问题是 resizedImage 总是 nil 并且我没有找到错误...

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

【问题讨论】:

  • 任何快速代码?

标签: iphone cocoa-touch


【解决方案1】:

根据@epatel 的精彩回答,我在 swift 中创建了一个UIImage-extension:

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

在故事板中测试:

【讨论】:

  • 太棒了.. 我想对圆形图像的缩放做一个小改动。如果您按原样使用代码,则会影响图像分辨率。所以我对给定的代码做了一个小的改动;让 window = UIApplication.sharedApplication().windows[0]; UIGraphicsBeginImageContextWithOptions(self.size, false, window.screen.scale)
  • cornerRadius 不应该是self.size.height / 2吗?
  • @IulianOnofrei 这对我来说很有意义:)
  • 我一直在寻找这样的东西。现在唯一的问题是,因为我在动画(由 tvOS)UIImageView 中使用它,所以我在角落外得到一个深色背景,但只有在聚焦时(它会缩放图像)。不知道它是从哪里出来的,我检查了故事板和代码。
  • @AugustinePA 根据the docs,你可以在 scale 选项中传入 0,系统会为你获取当前的 scale。
【解决方案2】:

我喜欢@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 是因为我有 collectionView 滚动并且图像具有不同的大小,因此当使用常量 radius 时,它实际上在比例方面看起来不同(例如:两个图像,一个是 1000x1000,另一个是 2000x2000,圆角半径 30 会在每一个上看起来都不一样)

因此,如果您这样做image.roundCorners(proportion: 20),所有图片看起来都具有相同的圆角半径。

这个答案也是更新版本。

【讨论】:

    【解决方案3】:

    Swift 4 中以正确的比例扩展 Besi's excellent answer

    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()!
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      我认为这可能非常相关: 在 iOS 11 中,有一种非常优雅的方式来圆整 (Image)View 的每个角。

      let imageView = UIImageView(image: UIImage(named: "myImage"))    
      imageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
      imageView.layer.cornerRadius = 10.0
      

      【讨论】:

        【解决方案5】:

        我正在努力绕过故事板中 UIImage 框的角落。我的 UIImage 有一个名为 image 的 IBOutlet。在这里阅读了一堆帖子后,我简单地添加了 3 行,效果很好。

        import UIKit
        

        然后在viewDidLoad中:

        image.layer.cornerRadius = 20.0
        
        image.layer.masksToBounds = true
        

        这适用于 Xcode 9 中的 iOS 11.1。

        【讨论】:

          【解决方案6】:

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

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

          很简单,做得对。

          【讨论】:

            【解决方案7】:

            利用图像尺寸创建圆形图像非常容易。

            cell.messageImage.layer.cornerRadius = image.size.width / 2
            cell.messageImage.layer.masksToBounds = true
            

            【讨论】:

            • 应该是帧大小
            【解决方案8】:

            为了创建圆角图像,我们可以使用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> 
            

            在您的视图控制器中

            然后在 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;
            

            【讨论】:

            • 我编辑了我的答案,请立即查看。不要投反对票。
            【解决方案9】:

            大家好,试试这个代码,

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

            干杯!!!

            【讨论】:

              【解决方案10】:
              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;
              }
              

              【讨论】:

                【解决方案11】:

                这些台词怎么样...

                // 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();
                

                【讨论】:

                  【解决方案12】:

                  如果您使用 UIImageView 来显示图像,您可以简单地执行以下操作:

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

                  并添加边框:

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

                  我相信您必须导入 &lt;QuartzCore/QuartzCore.h&gt; 并链接它才能使上述代码正常工作。

                  【讨论】:

                  • 导入和链接什么?
                  • 对不起#import
                  • 原来它在那里,但由于小于/大于而没有显示。
                  • 不错!设置图像时效果很好 UIViewModeContentModeScaleAspectFill
                  • 超级简单,但会降低 UITableView 的滚动性能是自定义单元格有一个 UIImageView...我用 CG 去! :)
                  【解决方案13】:

                  它使用剪辑而不是蒙版的原因似乎是色彩空间。

                  Apple 文档如下。

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

                  【讨论】:

                    【解决方案14】:

                    问题是使用 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;
                    

                    【讨论】:

                      【解决方案15】:

                      See here... IMO 除非您绝对需要在代码中执行此操作,否则只需在顶部叠加图像即可。

                      类似于...的东西

                      - (void)drawRect:(CGRect)rect 
                      {
                          // Drawing code
                          [backgroundImage drawInRect:rect];
                          [buttonOverlay drawInRect:rect];    
                      }
                      

                      【讨论】:

                      • 我尽量避免在代码中使用 CGImageCreateWithMask,但它总是返回 null。
                      • 我的意思是从一个资源中绘制另一个 UIImage 到它的顶部以圆角。查看编辑...
                      【解决方案16】:

                      您实际上并没有做任何事情,只是在那里进行缩放。您需要做的是通过使用 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 编程指南或其他一些示例。

                      【讨论】:

                      • 我的代码的第一部分是缩放,但第二部分尝试使用 CGImageCreateWithMask 屏蔽图像。问题是 CGImageCreateWithMask 返回 null 我不知道为什么...
                      猜你喜欢
                      • 2010-09-17
                      • 2022-01-12
                      • 2012-02-14
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-06-20
                      • 1970-01-01
                      • 2011-12-25
                      相关资源
                      最近更新 更多