2009-12-04 3 views
4

Я пытаюсь создать NSImage или NSImageCell с закругленными углами внутри NSTableView. Я не могу заставить работать. Вот лучшее, что я до сих пор в моем обычае NSCell:Как нарисовать округленное NSImage

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

Любые идеи о том, как это?

ответ

22

Вам нужно сохранить набор клипов при рисовании изображения и вместо этого восстановить контекст. Кроме того, я не думаю, что вы хотите использовать «в композиции», а скорее «перевернуты», если хотите просто нарисовать изображение, не принимая при этом непрозрачность адресата. Попробуйте что-то вроде:

[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]; 
+0

Это работает !! Огромное спасибо!! – nonamelive

3

Просто, чтобы обеспечить немного больше информации о том, что вы сделали неправильно:

Цель сохранения и восстановления gstate, чтобы иметь возможность отменить изменения в gstate. В вашем случае восстановление gsave после отсечения отключит клип. Вот почему решение (как объяснил Rhult) заключается в том, чтобы нарисовать то, что вы хотите обрезать до, вы восстанавливаете gstate.

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

Хорошая работа ... У вас есть ширина и высота назад для newSize. –

+0

Отличный ответ. Это сообщение фактически зажимает изображение, а заметный ответ просто маскирует изображение. Это имело значение в моем случае, потому что мне пришлось нарисовать белую рамку вокруг кругового изображения. Используя метод отмеченных ответов, пиксели изображения попадают в рамку (что делает ее плохой). Этот пост делает границу идеальной! – rocky

4

Swift версия:

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) 
+0

Спасибо, Пол; простой и сладкий :) (просто исправлены некоторые жестко заданные значения; ожидание экспертной оценки.) –

+0

Хорошая работа, спасибо. Для тех, кто прибывает из interwebs, обязательно измените 'width',' height', 'xRadius' и' yRadius' в соответствии с размерами объекта, который вы округлите. –

+0

Параметры NSMakeSize() инвертированы, и вам лучше использовать инициализатор NSize: пусть newSize = NSSize (width: esize.width, height: esize.height) –