I am learning about CALayer
and have the following problem. The following two images
are in fact two views in my app: the one on the left is an NSImageView
and the one on the right is a layer-hosting NSView
with the same image as contents. Here is the code for the ViewController
that I used to set this up:
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var aView: NSView!
@IBOutlet weak var anImage: NSImageView!
override func viewDidLoad() {
super.viewDidLoad()
let img = NSImage(named: "emptyStar")!
let l = CALayer()
l.contents = img
aView.layer = l
aView.wantsLayer = true
anImage.image = img
}
}
Why does the CALayer
image look so bad and how can I fix this (sticking with CALayer
)? A magnification of the right image shows bad anti-aliasing.
Things I tried are: 1) generating a CGImage
using
img.CGImageForProposedRect(&aView.frame, context: nil, hints: [NSImageHintInterpolation: 3])
and setting this as contents of l
, 2) setting l.contentsScale=2
, 3) setting l.edgeAntialiasingMask=[.LayerLeftEdge, .LayerRightEdge, .LayerBottomEdge, .LayerTopEdge]
, 4) making aView
layer-backed, by moving aView.wantsLayer=true
before aView.layer = l
. I could not make any of those work...
Both views are 50 x 50 while the image itself is a 253 x 254 PNG image that I grabbed from this tutorial
https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/
and it is in the Assets for this app.
I am pretty sure I am missing something simple here...
Thanks for any help!
UPDATE: Delegating the drawing seems to work:
class ViewController: NSViewController {
@IBOutlet weak var aView: NSView!
override func drawLayer(layer: CALayer, inContext ctx: CGContext) {
NSGraphicsContext.setCurrentContext(NSGraphicsContext(CGContext: ctx, flipped: false))
NSImage(named: "emptyStar")!.drawInRect(layer.bounds)
}
override func viewDidLoad() {
super.viewDidLoad()
let l = CALayer()
l.delegate = self
aView.layer = l
aView.wantsLayer = true
aView.layer!.setNeedsDisplay()
}
}
Hopefully there is a better solution to something that should work off the box...
You'll get aliasing artifacts if you don't use the correct min/mag filters.
Since you're putting a larger image into a smaller CALayer, you'd want to use linear, bilinear or trilinear filtering (in increasing order of cost).
For a layer, you can set the min filter using:
layer.minificationFilter = kCAFilterTrilinear;