【问题标题】:How to draw image inside a circular bezier path如何在圆形贝塞尔路径内绘制图像
【发布时间】:2015-02-23 05:16:05
【问题描述】:

我正在尝试创建一个自定义视图来绘制一张音乐 CD,其中包含 CD 上的专辑插图。

目前我使用核心图形在drawRect方法内绘制两个圆盘。内圆盘的颜色设置为视图的背景色,使内圆看起来像一个空心圆。

我的问题是我无法在圆形贝塞尔路径内绘制 UIImage 以获得我需要的结果。

这是我的 drawRect 代码:

// Draw a CD like view using three drawing operations:
// 1st draw the main disk
// 2nd draw the image if it is set
// 3rd draw the inner disk over the image so that it looks like it is a hollow disk with the image painted on the disk.
// Note:) This view expects its aspect ratio to be set as 1:1
- (void)drawRect:(CGRect)rect
{
    // Draw the main Circular CD disk
    UIBezierPath* outerRing = [UIBezierPath bezierPathWithOvalInRect:self.bounds];

    [self.mainColor setFill];
    [outerRing fill];

    [self.outerRingColor setStroke];
    [outerRing stroke];

    // Draw the album image if it is set
    if(self.artwork){
        [self.artwork drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];
    }

    // now draw another smaller disk inside
    // this will be a percentage smaller than the whole disk's bounds and will be centered inside it
    CGFloat sidePaddingCoord = ((1.0f - INNER_DISK_SIZE_PERCENTAGE) / 2) * self.bounds.size.height;
    CGFloat side = INNER_DISK_SIZE_PERCENTAGE * self.bounds.size.width;

    UIBezierPath* innerRing = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(sidePaddingCoord, sidePaddingCoord, side, side)];

    [self.innerRingColor setFill];
    [innerRing fill];

    [innerRing stroke];
}

这会将图像填充为正方形。我希望将图像剪辑到 outerRing 贝塞尔路径 内,使其看起来像一张音乐 CD。

我确信除了使用图像的 drawInRect 方法之外,还有一种方法可以使用核心图形来实现其他目的。有没有办法在圆形贝塞尔路径内“剪辑”图像或仅在贝塞尔路径内绘制?

【问题讨论】:

    标签: ios objective-c core-graphics


    【解决方案1】:

    我读过 rob mayoff、UIBezierPath Subtract PathiOS UIImage clip to paths 的非常棒的帖子,非常感谢。

    这是对他的代码的采用。保留outerRinginnerRing的创建代码,将它们添加到名为paths的数组中。

    [self.paths addObject:outerRing];
    [self.paths addObject:innerRing];
    

    那就用这个帮助方法吧。

    - (UIImage *)maskedImage
    {
        CGRect rect = CGRectZero;
        rect.size = self.originalImage.size;
        UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0);
    
        UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
        [clipPath appendPath:self.paths[1]];
        clipPath.usesEvenOddFillRule = YES;
    
        CGContextSaveGState(UIGraphicsGetCurrentContext()); {
            [clipPath addClip];
            [[UIColor orangeColor] setFill];
            [self.paths[0] fill];
        } CGContextRestoreGState(UIGraphicsGetCurrentContext());
    
        UIImage *mask = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0); {
            CGContextClipToMask(UIGraphicsGetCurrentContext(), rect, mask.CGImage);
            [self.originalImage drawAtPoint:CGPointZero];
        }
        UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return maskedImage;
    }
    

    drawRect

    UIImage *maskedImage = [self maskedImage];
    [maskedImage drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];
    

    【讨论】:

    • 非常感谢。我也阅读了链接中给出的答案。好东西。 :)
    • 是的,真的很棒。
    【解决方案2】:

    试试下面的代码:

        UIImageView *userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(85, 55.0, 90, 90)];
        userImageView.layer.cornerRadius = 90/2;
        userImageView.clipsToBounds = YES;
        userImageView.layer.borderWidth = 1.0f;
        userImageView.layer.borderColor = [UIColor blueColor];
        [self.view addSubview:userImageView]; //or add it to the view you want
        UIImage *userImage = [UIImage imageNamed:@"<image you want to set>"];
        userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(90, 60.0, 80, 80)];
        userImageView.image = userImage;
        userImageView.layer.cornerRadius = 80/2;
        userImageView.clipsToBounds = YES;
        userImageView.layer.borderWidth = 1.0f;
        userImageView.layer.borderColor = [UIColor blueColor;
        [self.view addSubview:userImageView]; //or add it to the view you want
    

    【讨论】: