如何绘制圆形 NSImage

发布于 2024-08-13 17:30:09 字数 1106 浏览 6 评论 0原文

我正在尝试在 NSTableView 内创建一个带有圆角的 NSImageNSImageCell 。我无法得到任何工作。这是迄今为止我在自定义 NSCell 中得到的最好的结果:

- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView { 
  if (thumbnailLink) {
    NSURL *url = [NSURL URLWithString:thumbnailLink];
    if (url) {
        NSRect imageFrame = [self _imageFrameForInteriorFrame:frame];
        NSImage *image = [[NSImage alloc] initWithContentsOfURL:url];
        [image setScalesWhenResized:YES];
        [image setSize:NSMakeSize(IMAGE_HEIGHT, IMAGE_WIDTH)];

        [NSGraphicsContext saveGraphicsState];
        imageFrame = NSInsetRect(imageFrame, 1, 1);
        NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:imageFrame cornerRadius:5.0];
        [clipPath setWindingRule:NSEvenOddWindingRule];
        [clipPath addClip];
        [NSGraphicsContext restoreGraphicsState];   
        [image drawInRect:imageFrame fromRect:NSMakeRect(0, 0, 0, 0) operation:NSCompositeSourceIn fraction:1.0];
        [image release];
    }
}
...

关于如何做到这一点有什么想法吗?

I am trying to create a NSImage or NSImageCell with rounded corners inside a NSTableView. I can't get anything to work. Here is the best I have so far inside my custom NSCell:

- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView { 
  if (thumbnailLink) {
    NSURL *url = [NSURL URLWithString:thumbnailLink];
    if (url) {
        NSRect imageFrame = [self _imageFrameForInteriorFrame:frame];
        NSImage *image = [[NSImage alloc] initWithContentsOfURL:url];
        [image setScalesWhenResized:YES];
        [image setSize:NSMakeSize(IMAGE_HEIGHT, IMAGE_WIDTH)];

        [NSGraphicsContext saveGraphicsState];
        imageFrame = NSInsetRect(imageFrame, 1, 1);
        NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:imageFrame cornerRadius:5.0];
        [clipPath setWindingRule:NSEvenOddWindingRule];
        [clipPath addClip];
        [NSGraphicsContext restoreGraphicsState];   
        [image drawInRect:imageFrame fromRect:NSMakeRect(0, 0, 0, 0) operation:NSCompositeSourceIn fraction:1.0];
        [image release];
    }
}
...

Any ideas on how to this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

生死何惧 2024-08-20 17:30:09

您需要在绘制图像时保留剪辑集,并在之后恢复上下文。另外,如果您只想正常绘制图像而不考虑目标不透明度,我认为您不想使用“in”合成,而是使用“over”合成。尝试类似的方法:

[NSGraphicsContext saveGraphicsState];

NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:imageFrame
                                                     xRadius:5
                                                     yRadius:5];
[path addClip];

[image drawInRect:imageFrame
         fromRect:NSZeroRect
        operation:NSCompositeSourceOver
         fraction:1.0];

[NSGraphicsContext restoreGraphicsState];

You need to keep the clip set when drawing your image, and restore the context after instead. Also I don't think you want to be using "in" compositing but rather "over" if you just want to draw your image normally without taking the destination opacity in consideration. Try something like:

[NSGraphicsContext saveGraphicsState];

NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:imageFrame
                                                     xRadius:5
                                                     yRadius:5];
[path addClip];

[image drawInRect:imageFrame
         fromRect:NSZeroRect
        operation:NSCompositeSourceOver
         fraction:1.0];

[NSGraphicsContext restoreGraphicsState];
安人多梦 2024-08-20 17:30:09
+ (NSImage*)roundCorners:(NSImage *)image
{

NSImage *existingImage = image;
NSSize existingSize = [existingImage size];
NSSize newSize = NSMakeSize(existingSize.width, existingSize.height);
NSImage *composedImage = [[[NSImage alloc] initWithSize:newSize] autorelease];

[composedImage lockFocus];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];

NSRect imageFrame = NSRectFromCGRect(CGRectMake(0, 0, 1024, 1024));
NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:imageFrame xRadius:200 yRadius:200];
[clipPath setWindingRule:NSEvenOddWindingRule];
[clipPath addClip];

[image drawAtPoint:NSZeroPoint fromRect:NSMakeRect(0, 0, newSize.width, newSize.height) operation:NSCompositeSourceOver fraction:1];

[composedImage unlockFocus];

return composedImage;
}
+ (NSImage*)roundCorners:(NSImage *)image
{

NSImage *existingImage = image;
NSSize existingSize = [existingImage size];
NSSize newSize = NSMakeSize(existingSize.width, existingSize.height);
NSImage *composedImage = [[[NSImage alloc] initWithSize:newSize] autorelease];

[composedImage lockFocus];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];

NSRect imageFrame = NSRectFromCGRect(CGRectMake(0, 0, 1024, 1024));
NSBezierPath *clipPath = [NSBezierPath bezierPathWithRoundedRect:imageFrame xRadius:200 yRadius:200];
[clipPath setWindingRule:NSEvenOddWindingRule];
[clipPath addClip];

[image drawAtPoint:NSZeroPoint fromRect:NSMakeRect(0, 0, newSize.width, newSize.height) operation:NSCompositeSourceOver fraction:1];

[composedImage unlockFocus];

return composedImage;
}
最美的太阳 2024-08-20 17:30:09

斯威夫特版本:

func roundCorners(image: NSImage, width: CGFloat = 192, height: CGFloat = 192) -> NSImage {
    let xRad = width / 2
    let yRad = height / 2
    let existing = image
    let esize = existing.size
    let newSize = NSMakeSize(esize.width, esize.height)
    let composedImage = NSImage(size: newSize)

    composedImage.lockFocus()
    let ctx = NSGraphicsContext.currentContext()
    ctx?.imageInterpolation = NSImageInterpolation.High

    let imageFrame = NSRect(x: 0, y: 0, width: width, height: height)
    let clipPath = NSBezierPath(roundedRect: imageFrame, xRadius: xRad, yRadius: yRad)
    clipPath.windingRule = NSWindingRule.EvenOddWindingRule
    clipPath.addClip()

    let rect = NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
    image.drawAtPoint(NSZeroPoint, fromRect: rect, operation: NSCompositingOperation.CompositeSourceOver, fraction: 1)
    composedImage.unlockFocus()

    return composedImage
}

// then
roundCorners(image)
roundCorners(image, width: 512, height: 512)

Swift version:

func roundCorners(image: NSImage, width: CGFloat = 192, height: CGFloat = 192) -> NSImage {
    let xRad = width / 2
    let yRad = height / 2
    let existing = image
    let esize = existing.size
    let newSize = NSMakeSize(esize.width, esize.height)
    let composedImage = NSImage(size: newSize)

    composedImage.lockFocus()
    let ctx = NSGraphicsContext.currentContext()
    ctx?.imageInterpolation = NSImageInterpolation.High

    let imageFrame = NSRect(x: 0, y: 0, width: width, height: height)
    let clipPath = NSBezierPath(roundedRect: imageFrame, xRadius: xRad, yRadius: yRad)
    clipPath.windingRule = NSWindingRule.EvenOddWindingRule
    clipPath.addClip()

    let rect = NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
    image.drawAtPoint(NSZeroPoint, fromRect: rect, operation: NSCompositingOperation.CompositeSourceOver, fraction: 1)
    composedImage.unlockFocus()

    return composedImage
}

// then
roundCorners(image)
roundCorners(image, width: 512, height: 512)
随风而去 2024-08-20 17:30:09

只是为了提供有关您做错了什么的更多信息:

保存和恢复 gstate 的目的是能够撤消对 gstate 的更改。在您的情况下,在剪辑后恢复 gsave 会取消剪辑。这就是为什么解决方案(如 Rhult 所解释的)是在恢复 gstate 之前绘制您想要剪切的内容。

Just to provide a bit more info on what you did wrong:

The purpose of saving and restoring the gstate is to be able to undo your changes to the gstate. In your case, restoring the gsave after clipping undid the clip. That's why the solution (as explained by Rhult) is to draw what you want clipped before you restore the gstate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文