Problem: I have a multipage TIFF image (generated with tiffutil) that contains the same image at multiple pixel dimension from 256×128 px all the way up to 4096×2048 px. I want to display this image in a CALayer so that the system automatically chooses the best representation of the image depending on the layer’s size. At the moment, the layer always uses the 256×128 representation of the image, regardless of its size.
Here’s what I do: I load the image with
NSImage *image = [NSImage imageNamed:@"map-multipage.tiff"];
Logging the image object confirms that it contains multiple representations with different pixel sizes, but all representations are the same size in points (256×128). AFAIK this is how Apple recommends multi-resolution images to be constructed.
NSLog(@"%@", image);
<NSImage 0x100623060 Name=map-multipage Size={256, 128} Reps=(
"NSBitmapImageRep 0x10064d330 Size={256, 128} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=256x128 Alpha=NO Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x10014fdb0",
"NSBitmapImageRep 0x10064e1b0 Size={256, 128} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=512x256 Alpha=NO Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x10014fdb0",
...
"NSBitmapImageRep 0x100530bd0 Size={256, 128} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=4096x2048 Alpha=NO Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x10014fdb0"
)>
I then assign the NSImage instance directly to the layer’s contents property:
self.layerView.layer.contents = image;
As mentioned, the result is that the layer uses the first representation (256×128 px) to display the image, regardless of the layer’s size in points or pixels.
When I assign the same image to an NSImageView, it works as expected. The image view transparently selects the best image representation depending on its size. I would expect that CALayer would work the same way but apparently this is not the case. Can anybody confirm that CALayer does not support this automatic selection or am I doing something wrong?
(Note that this question is not directly related to HiDPI/Retina graphics. In fact, if I move the layer to a display in HiDPI mode, it does render a little sharper, indicating that it now uses the second bitmap representation (512×256 px) for rendering. This suggests that the automatism to select a higher resolution on a HiDPI display works while the fundamental selection of the best bitmap representation fails.)
It seems like the AppKit method
-[CALayer setContents:]chooses a bitmap representation of size matching-[contents size]ifcontentsobject isNSImage. Then the selected bitmap is used as is until-[CALayer setContents:]is called once again.