7

Problem: I have a multipage TIFF image (generated with tiffutil) that contains the same image at multiple pixel dimension from 256x128 px all the way up to 4096x2048 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 256x128 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 (256x128). 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 (256x128 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 (512x256 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.)

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • Just an idea, try to remove `.tiff` in `@"map-multipage.tiff"`. Also, ensure that `layerContentsRedrawPolicy` is not `Never`. Or maybe layer's `contentsGravity` influents how its content is being updated? – Vadim Jun 25 '12 at 22:58
  • 1
    @Stream: thanks a lot for the suggestions. No, removing the file extension has no effect, neither does playing with `layerContentsRedrawPolicy` or `contentsGravity`. Having watched WWDC 2012 session 245 last night, I suspect the answer to my question is, it doesn't work that way. It seems that the `CALayer`'s `contents` doesn't "know" anything about the layer's actual size in points/pixels and therefore cannot select a bitmap representation based on this information. – Ole Begemann Jun 26 '12 at 14:38
  • Makes sense! `-[CALayer contents]` is just a bitmap, too “dumb” to know anything about its source. It is `CALayer` which relies on representation through `drawRect:inContext:`. So, when you set `contents` directly, its dimension must be based on current `-[NSImage size]`. – Vadim Jun 27 '12 at 16:44
  • There is a new official documentation regarding the subject, not yet public to share a link: High Resolution Guidelines for OS X > Advanced Optimization Techniques > Manage Core Animation Layer Contents and Scale > Layers with NSImage Contents Are Updated Automatically. – Vadim Jul 15 '12 at 21:41

1 Answers1

2

It seems like the AppKit method -[CALayer setContents:] chooses a bitmap representation of size matching -[contents size] if contents object is NSImage. Then the selected bitmap is used as is until -[CALayer setContents:] is called once again.

Vadim
  • 9,383
  • 7
  • 36
  • 58