Автоматическое масштабирование многостраничного TIFF NSImage в CALayer

Проблема: у меня есть многостраничное изображение TIFF (сгенерированное с помощью tiffutil), которое содержит одно и то же изображение с размером в несколько пикселей от 256x128 пикселей до 4096x2048 пикселей. Я хочу отобразить это изображение в виде CALayer, чтобы система автоматически выбирала наилучшее представление изображения в зависимости от размера слоя. На данный момент слой всегда использует представление изображения 256x128, независимо от его размера.

Вот что я делаю: я загружаю изображение с помощью

NSImage *image = [NSImage imageNamed:@"map-multipage.tiff"];

Регистрация объекта image подтверждает, что он содержит несколько представлений с разными размерами в пикселях, но все представления имеют одинаковый размер в точках (256x128). Насколько я знаю, именно так Apple рекомендует создавать изображения с несколькими разрешениями.

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"
)>

Затем я назначаю экземпляр NSImage непосредственно свойству contents слоя:

self.layerView.layer.contents = image;

Как уже упоминалось, в результате слой использует первое представление (256x128 пикселей) для отображения изображения, независимо от размера слоя в точках или пикселях.

Когда я назначаю одно и то же изображение NSImageView, оно работает, как и ожидалось. Представление изображения прозрачно выбирает наилучшее представление изображения в зависимости от его размера. Я ожидал, что CALayer будет работать так же, но, видимо, это не так. Кто-нибудь может подтвердить, что CALayer не поддерживает этот автоматический выбор или я что-то не так делаю?

(Обратите внимание, что этот вопрос не имеет прямого отношения к графике HiDPI/Retina. На самом деле, если я перемещу слой на дисплей в режиме HiDPI, он будет отображаться немного четче, указывая на то, что теперь он использует второе растровое представление (512x256 пикселей) Это говорит о том, что автоматизм выбора более высокого разрешения на дисплее HiDPI работает, в то время как фундаментальный выбор наилучшего растрового представления терпит неудачу.)


person Ole Begemann    schedule 25.06.2012    source источник
comment
Просто идея, попробуйте удалить .tiff в @"map-multipage.tiff". Также убедитесь, что layerContentsRedrawPolicy не является Never. Или, может быть, contentsGravity слоя влияет на то, как обновляется его содержимое?   -  person Vadim    schedule 26.06.2012
comment
@Stream: большое спасибо за предложения. Нет, удаление расширения файла не имеет никакого эффекта, равно как и игра с layerContentsRedrawPolicy или contentsGravity. Посмотрев прошлой ночью сессию 245 WWDC 2012, я подозреваю, что ответ на мой вопрос таков: это не работает таким образом. Похоже, что contents из CALayer ничего не знает о фактическом размере слоя в точках/пикселях и, следовательно, не может выбрать растровое представление на основе этой информации.   -  person Ole Begemann    schedule 26.06.2012
comment
Имеет смысл! -[CALayer contents] — это просто растровое изображение, слишком «тупое», чтобы знать что-либо о его источнике. Это CALayer, который опирается на представление через drawRect:inContext:. Таким образом, когда вы устанавливаете contents напрямую, его размер должен основываться на текущем -[NSImage size].   -  person Vadim    schedule 27.06.2012
comment
Существует новая официальная документация по этому вопросу, еще не общедоступная, чтобы поделиться ссылкой: Рекомендации по высокому разрешению для OS X › Расширенные методы оптимизации › Управление содержимым и масштабированием основного слоя анимации › Слои с содержимым NSImage обновляются автоматически.   -  person Vadim    schedule 16.07.2012


Ответы (1)


Похоже, что метод AppKit -[CALayer setContents:] выбирает растровое представление размера, соответствующего -[contents size], если contents объект равен NSImage. Затем выбранное растровое изображение используется как есть до тех пор, пока -[CALayer setContents:] не будет вызвано еще раз.

person Vadim    schedule 27.06.2012