Wie eine abgerundete NSImage zeichnen
-
13-09-2019 - |
Frage
Ich versuche, ein NSImage
oder NSImageCell
mit abgerundeten Ecken in einer NSTableView
zu erstellen. Ich kann nichts an der Arbeit. Hier ist das Beste, was ich habe bisher in meinem benutzerdefinierten 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];
}
}
...
Alle Ideen, wie man das?
Lösung
Sie müssen den Clip Set halten, wenn Ihr Bild zeichnen, und Wiederherstellen der Kontext nach statt. Ich auch nicht denken, Sie „in“ Compositing verwenden wollen, sondern „über“, wenn Sie nur wollen, normalerweise Ihr Bild zeichnen, ohne das Ziel Opazität in Betracht gezogen wird. Versuchen Sie so etwas wie:
[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];
Andere Tipps
+ (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;
}
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)
Nur ein bisschen mehr Informationen darüber zu geben, was Sie falsch gemacht haben:
Der Zweck der Speicherung und Wiederherstellung der gstate ist in der Lage sein, die Änderungen an der gstate rückgängig zu machen. In Ihrem Fall die Wiederherstellung der gsave nach Clipping löste den Clip. Deshalb ist die Lösung (wie durch Rhult erklärt) ist zu zeichnen, was Sie wollen abgeschnitten vor Sie die gstate wiederherstellen.