Усовершенствованные методы оптимизации
Эта глава дает представление для специализированных задач, которые не выполняет каждое приложение. Если Ваш OpenGL использования приложения, создает Кварцевые битовые массивы, доступы экранируют пиксели, или выполняет ряд других меньше общих задач, Вы, возможно, должны были бы последовать совету оптимизации в некоторых из этих разделов.
Включите OpenGL для получения с высокой разрешающей способностью
OpenGL является основанный на пикселе API. NSOpenGLView
класс не обеспечивает поверхности с высокой разрешающей способностью по умолчанию. Поскольку добавление большего количества пикселей к renderbuffers имеет импликации производительности, необходимо явно выбрать в поддерживать экраны с высокой разрешающей способностью.
Можно выбрать в к высокому разрешению путем вызова метода setWantsBestResolutionOpenGLSurface:
когда Вы инициализируете представление и предоставление YES
как параметр:
[self setWantsBestResolutionOpenGLSurface:YES]; |
Если Вы не выбираете в, система увеличивает представленные результаты.
wantsBestResolutionOpenGLSurface
свойство важно только для представлений к который NSOpenGLContext
объект связывается. Его значение не влияет на поведение других представлений. Для совместимости, wantsBestResolutionOpenGLSurface
значения по умолчанию к NO
, обеспечение кадрового буфера 1 пикселя за точку независимо от отступающего масштабного коэффициента для дисплея представление занимает. Установка этого свойства к YES
поскольку высказанное мнение заставляет AppKit выделять кадровый буфер более высокого разрешения в надлежащих случаях для отступающего масштабного коэффициента и целевого дисплея.
Функционировать правильно с wantsBestResolutionOpenGLSurface
набор к YES
, представление должно выполнить корректные преобразования между модулями представления (точки) и пиксельные модули по мере необходимости. Например, установившаяся практика передачи ширины и высоты [self bounds]
к glViewport()
приведет к неправильным результатам в высоком разрешении, потому что параметры передали glViewport()
функция должна быть в пикселях. В результате Вы станете только частичными вместо полного обзора поверхности рендеринга. Вместо этого используйте границы запоминающего устройства:
[self convertRectToBacking:[self bounds]]; |
Можно также выбрать в к высокому разрешению путем включения установки Supports Hi-Res Backing для представления OpenGL в XCode, как показано на рисунке 3-1.
Установите область просмотра для поддержки высокого разрешения
Размерности области просмотра находятся в пикселях относительно поверхности OpenGL. Передайте ширину и высоту к glViewPort
и используйте 0,0 для x
и y
смещения. Перечисление 3-1 показывает, как получить размерности представления в пикселях и принять размер запоминающего устройства во внимание.
Перечисление 3-1 , Настраивающее область просмотра для рисования
- (void)drawRect:(NSRect)rect // NSOpenGLView subclass |
{ |
// Get view dimensions in pixels |
NSRect backingBounds = [self convertRectToBacking:[self bounds]]; |
GLsizei backingPixelWidth = (GLsizei)(backingBounds.size.width), |
backingPixelHeight = (GLsizei)(backingBounds.size.height); |
// Set viewport |
glViewport(0, 0, backingPixelWidth, backingPixelHeight); |
// draw… |
} |
Вы не должны выполнять рендеринг в пикселях, но действительно необходимо знать о системе координат, в которой Вы хотите представить. Например, если Вы захотите представить в точках, то этот код будет работать:
glOrtho(NSWidth(bounds), NSHeight(bounds),...) |
Скорректируйте модель и текстурируйте активы
Если Вы выбираете в к получению с высокой разрешающей способностью, также необходимо скорректировать модель и активы текстуры приложения. Например, при работе дисплея с высокой разрешающей способностью, Вы могли бы хотеть выбрать большие модели и более подробные текстуры для использования в своих интересах увеличенного числа пикселей. С другой стороны, на дисплее стандартного разрешения, можно продолжать использовать меньшие модели и текстуры.
Если Вы создаете и текстуры кэша при инициализации приложения Вы могли бы хотеть рассмотреть стратегию, размещающую изменение текстуры на основе разрешения дисплея.
Проверьте на вызовы, определенные в пиксельных размерностях
Эти функции используют пиксельные размерности:
glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
glScissor (GLint x, GLint y, GLsizei width, GLsizei height)
glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, ...)
glLineWidth (GLfloat width)
glRenderbufferStorage (..., GLsizei width, GLsizei height)
glTexImage2D (..., GLsizei width, GLsizei height, ...)
Настройте производительность OpenGL для высокого разрешения
Производительность является важным фактором при определении, поддерживать ли содержание с высокой разрешающей способностью. Увеличение вчетверо пикселей, происходящее, когда Вы выбираете в к высокому разрешению, требует большего количества работы процессором фрагмента. Если Ваше приложение выполняет много вычислений на фрагмент, увеличение пикселей могло бы сократить свою частоту кадров. Если Ваше выполнение приложения значительно медленнее в высоком разрешении, рассмотрите следующие опции:
Оптимизируйте производительность программы построения теней фрагмента. (См. Настройку Вашего Приложения OpenGL в Руководстве по программированию OpenGL для Mac),
Выберите более простой алгоритм для реализации в программе построения теней фрагмента. Это сокращает качество каждого отдельного пикселя для обеспечения рендеринга полного изображения в более высоком разрешении.
Используйте дробный масштабный коэффициент между 1,0 и 2.0. Масштабный коэффициент 1,5 обеспечивает лучшее качество, чем масштабный коэффициент 1,0, но это должно заполнить меньше пикселей, чем изображение, масштабируемое к 2,0.
Мультивыборка сглаживания может быть дорогостоящей с предельной выгодой в высоком разрешении. При использовании его Вы могли бы хотеть пересмотреть.
Лучшее решение зависит от потребностей Вашего приложения OpenGL; необходимо протестировать больше чем одну из этих опций и выбрать подход, обеспечивающий лучший баланс между производительностью и качеством изображения.
Используйте поддержанное уровнем представление для текста перекрытия на содержании OpenGL
Когда Вы рисуете стандартные средства управления и текст Какао к поддержанному уровнем представлению, системные дескрипторы, масштабирующие содержание того уровня для Вас. Необходимо выполнить только несколько шагов, чтобы установить и использовать уровень. Сравните средства управления и текст в стандартных и высоких разрешениях, как показано на рисунке 3-2. Текст выглядит одинаково на обоих без любой дополнительной работы с Вашей стороны.
Установите
wantsLayer
свойство ВашегоNSOpenGLView
подкласс кYES
.Включение
wantsLayer
свойствоNSOpenGLView
объект активирует поддержанный уровнем рендеринг представления OpenGL. Рисование поддержанного уровнем представления OpenGL продолжается главным образом обычно посредством представленияdrawRect:
метод. Поддержанный уровнем режим рендеринга использует свое собственноеNSOpenGLContext
объект, который отличен отNSOpenGLContext
то, что использование представления для того, чтобы подойти к концу не уровень поддержало режим.AppKit автоматически создает этот контекст и присваивает его представлению путем вызова
setOpenGLContext:
метод. ПредставлениеopenGLContext
средство доступа возвратит поддержанный уровнем контекст OpenGL (а не не уровень поддержал контекст), в то время как представление работает в поддержанном уровнем режиме.Создайте содержание уровня или как файл XIB или программно.
Средства управления, показанные на рисунке 3-2, создавались в файле XIB путем разделения на подклассы
NSBox
и использование статического текста со множеством стандартных средств управления. Используя этот подход позволяетNSBox
подкласс для игнорирования событий от нажатия мыши, все еще позволяя пользователю взаимодействовать с содержанием OpenGL.Добавьте уровень к представлению OpenGL путем вызова
addSublayer:
метод.
Используйте окно приложения для полноэкранной работы
Для лучшего пользовательского опыта, если Вы хотите, чтобы Ваше приложение выполнило полный экран, создают окно, покрывающее весь экран. Этот подход предлагает два преимущества:
Система обеспечивает оптимизированную производительность контекста.
Пользователи будут в состоянии видеть критические системные диалоговые окна выше Вашего содержания.
Необходимо избежать изменять режим отображения системы.
Преобразуйте координатное пространство, когда поражено тестируя
Всегда преобразовывайте координаты события окна при выполнении тестирования хита в OpenGL. locationInWindow
метод NSEvent
класс возвращает расположение получателя в основной системе координат окна. Тогда необходимо вызвать convertPoint:fromView:
метод для получения локальных координат для представления OpenGL (см. Преобразование в и от Представлений).
NSPoint aPoint = [theEvent locationInWindow]; |
NSPoint localPoint = [myOpenGLView convertPoint:aPoint fromView:nil]; |
Управляйте базовым содержанием слоя анимации и масштабом
Представления (NSView
) и уровни (CALayer
) может быть интегрирован двумя способами — посредством поддержки уровня или хостинга уровня. Когда Вы конфигурируете поддержанное уровнем представление путем вызова setWantsLayer:
со значением YES
, класс представления автоматически создает отступающий уровень. Представление кэширует любое получение, которое оно выполняет к отступающему уровню. Когда дело доходит до высокого разрешения поддержанные уровнем представления масштабируются автоматически системой. У Вас нет работы, чтобы сделать для получения довольными что взгляды, большие на дисплеях с высокой разрешающей способностью.
Уровни, размещенные представлениями, отличаются. Размещающее уровень представление является представлением, содержащим Базовый Слой анимации, которым Вы намереваетесь управлять непосредственно. Вы создаете размещающее уровень представление путем инстанцирования Базового класса Слоя анимации и предоставления того уровня к представлению setLayer:
метод. Затем вызовите setWantsLayer:
со значением YES
.
При использовании размещающего уровень представления Вы не должны полагаться на представление для рисования, и при этом Вы не должны добавлять подпредставления к размещающему уровень представлению. Корневой слой (использование набора уровня setLayer:
) должен быть обработан как корневой слой дерева уровня, и необходимо только использовать Базовое получение Анимации и методы анимации. Вы все еще используете представление для обработки событий от нажатия мыши и событий клавиатуры, но любое получающееся получение должно быть обработано Базовой Анимацией.
Поскольку уровни, размещенные представлениями, являются пользовательскими CALayer
объекты, Вы ответственны за:
Установка начальной буквы
contents
свойство уровняХранение значения
contentsScale
свойство обновляетсяОбеспечение содержания с высокой разрешающей способностью
Сделать обновление уровней, которыми Вы управляете проще, реализация layer:shouldInheritContentsScale:fromWindow:
. Это CALayer
метод делегата позволяет Вам управлять масштабом и содержанием для размещенного уровня, содержание которого не NSImage
объект (Вы не должны управлять NSImage
содержание). Для дополнительных подробных данных посмотрите Ссылку на протокол NSLayerDelegateContentsScaleUpdating.
Когда изменение разрешения происходит для данного окна, система пересекает деревья уровня в том окне, чтобы решить что действие, если таковые имеются, взять для каждого уровня. Система запросит делегата уровня, чтобы определить, изменить ли уровень contentsScale
свойство к новому масштабу (или 2.0 или 1.0).
Если возвращается делегат YES
, это должно внести любые соответствующие изменения в свойства уровня, как требуется изменением разрешения. Например, уровень, содержание которого содержит объект CGImage, должен определить, доступен ли альтернативный объект CGImage для нового масштабного коэффициента. Если делегат находит подходящий объект CGImage, то в дополнение к возврату YES
, это должно установить надлежащий объект CGImage как новое содержание уровня.
Для уровней, не имеющих делегата, Ваше приложение должно также:
Установите подходящего делегата, который может обработать изменение разрешения (рекомендуемый подход).
Обеспечьте средние значения обновления уровней по мере необходимости, когда уведомление изменения разрешения отправляется (если Вы предпочитаете этот подход, посмотрите Динамические изменения Дескриптора в Разрешении Окна Только, Когда Вы Должны).
Базовая Анимация, составляющая механизм, смотрит на каждый уровень contentsScale
свойство, чтобы определить, должно ли его содержание масштабироваться во время составления композита. Если Ваше приложение создает уровни без связанного представления, contentsScale
свойство каждого нового расположенного на слое объекта первоначально установлено в 1,0. При последующем рисовании уровня на дисплее с высокой разрешающей способностью содержание уровня увеличено автоматически, который приводит к потере подробности. Однако можно установить значение уровня contentsScale
свойство соответственно и обеспечивает содержание с высокой разрешающей способностью, как показано в Перечислении 3-2.
Перечисление 3-2 , Переопределяющее viewDidChangeBackingProperties
- (void)viewDidChangeBackingProperties |
{ |
[super viewDidChangeBackingProperties]; |
[[self layer] setContentsScale:[[self window] backingScaleFactor]]; |
// Your code to provide content |
} |
Уровни с содержанием NSImage обновляются автоматически
Когда Вы устанавливаете NSImage
возразите как содержание уровня, система автоматически выбирает представление изображения, самое подходящее для экрана, на котором находится уровень. Существует две ситуации, для которых необходимо будет переопределить автоматический выбор:
Уровень имеет дополнительное масштабирование вследствие изменений границ слоев или преобразовывает.
contentsGravity
свойство не является одним из следующего:kCAContentsGravityResize
,kCAContentsGravityResizeAspect
, илиkCAContentsGravityResizeFill
.Это свойство установлено в значение
kCAGravityResize
по умолчанию, который масштабирует содержание уровня для заполнения границ слоев, вне зависимости от естественного форматного соотношения. Изменение силы тяжести к опции неизменения размеров устраняет автоматическое масштабирование, которое иначе произошло бы.
Для любого из этих случаев используйте эти методы NSImage
класс для управления содержанием и масштабированием уровня:
recommendedLayerContentsScale:
предоставляет системе оптимальное масштабирование для уровняlayerContentsForContentsScale:
обеспечивает содержание для уровня в данном размере
Уровни с содержанием CGImage не обновляются автоматически
OS X не обрабатывает динамические изменения для автономных уровней, имеющих содержание CGImage, потому что он не имеет знания того, как было предоставлено содержание уровня. Также, система не в состоянии заменить надлежащими разрешению альтернативами, даже если они доступны. Ваше приложение должно управлять этими уровнями и изменить свойства слоя как подходящие для изменений между разрешениями. То же является истиной для любых автономных уровней, которые Вы добавляете к поддержанному уровнем дереву представления. Если Вы не используете NSImage
объекты как содержание уровня, Ваше приложение должно обновить свойства слоя и содержание при необходимости.
Создайте и представьте битовые массивы для размещения высокого разрешения
Растровые контексты всегда измеряются с помощью пикселей, не точек. При создании растрового контекста необходимо вручную определить правильный масштаб на основе места назначения, к которому битовый массив будет нарисован и создаст более крупный буфер в надлежащих случаях. Любые существующие растровые кэши (кэши глифа, основанные на битовом массиве художественные кэши — возможно включая кэши растеризированного содержания PDF — или подобный), возможно, должны были бы разделить кэши для каждого разрешения. Поскольку потребность в определенном разрешении может прийти и уйти динамично, разрешения, поддерживаемые кэшами, должны быть динамичными. Другими словами, не принимайте свои потребности кэша быть только 1x (или должен быть только 2x) на основе его первого использования, потому что для последующего использования могла быть нужной запись кэша для различного разрешения. Например, пользователь мог перетащить окно от стандарта - к дисплею с высокой разрешающей способностью (или наоборот) в многократной системе отображения (см., что Разрешение Может Измениться Динамично). Вы захотите поддержать непротиворечивый пользовательский опыт, если это произойдет.
Перечисление 3-3 показывает, как использовать AppKit для создания битового массива, это масштабируется для размещения разрешения устройства. Существует много других способов создать битовые массивы в Какао. Для получения дополнительной информации посмотрите Создание Битового массива в Руководстве по Рисованию Какао.
Независимо от того, как Вы принимаете решение создать битовый массив, существует два дефицитных изделия, проиллюстрированные в Перечислении 3-3, что необходимо удостовериться, что Вы включаете в свой собственный код.
Установите ширину (
pixelsWide
) и высота (pixelsHigh
) из битового массива для числа пикселей Вам нужно. Не делайте ошибку базирования пикселя, рассчитывают на представление (или другой объект) границы, потому что размерности представления указаны в точках.Установите пользовательский размер битового массива, который является его шириной и высотой в точках. Пользовательский размер передает точки на дюйм, которые необходимо правильно измерить битовый массив для поддержки высокого разрешения.
Перечисление 3-3 , Настраивающее битовый массив для поддержки высокое разрешение
- (id)myDrawToBitmapOfWidth:(NSInteger)width |
andHeight:(NSInteger)height |
withScale:(CGFloat)scale |
{ |
NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc] |
initWithBitmapDataPlanes:NULL |
pixelsWide:width * scale |
pixelsHigh:height * scale |
bitsPerSample:8 |
samplesPerPixel:4 |
hasAlpha:YES |
isPlanar:NO |
colorSpaceName:NSCalibratedRGBColorSpace |
bitmapFormat:NSAlphaFirstBitmapFormat |
bytesPerRow:0 |
bitsPerPixel:0 |
]; |
// There isn't a colorspace name constant for sRGB so retag |
// using the sRGBColorSpace method |
bmpImageRep = [bmpImageRep bitmapImageRepByRetaggingWithColorSpace: |
[NSColorSpace sRGBColorSpace]]; |
// Setting the user size communicates the dpi |
[bmpImageRep setSize:NSMakeSize(width, height)]; |
// Create a bitmap context |
NSGraphicsContext *bitmapContext = |
[NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep]; |
// Save the current context |
[NSGraphicsContext saveGraphicsState]; |
// Switch contexts for drawing to the bitmap |
[NSGraphicsContext setCurrentContext: |
[NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep]]; |
// *** Your drawing code here *** |
[NSGraphicsContext restoreGraphicsState]; |
// Send back the image rep to the requestor |
return bmpImageRep; |
} |
- (void)drawRect:(NSRect)dirtyRect |
{ |
// Bounds are in points |
NSRect bounds = [self bounds]; |
// Figure out the scale of pixels to points |
CGFloat scale = [self convertSizeToBacking:CGSizeMake(1,1)].width; |
// Supply the user size (points) |
NSBitmapImageRep *myImageRep = [self myDrawToBitmapOfWidth:bounds.size.width |
andHeight:bounds.size.height |
withScale:scale]; |
// Draw the bitmap image to the view bounds |
[myImageRep drawInRect:bounds]; |
} |
Используйте основанный на блоке метод рисования для внеэкранных изображений
Если Ваше приложение использует lockFocus
и unlockFocus
методы NSImage
класс для внеэкранного получения, рассмотрите использование метода imageWithSize:flipped:drawingHandler:
вместо этого (доступный в OS X v10.8). При использовании методов фокуса блокировки для рисования можно получить неожиданные результаты — любой, который Вы получите низкое разрешение NSImage
возразите, что взгляды, неправильные, когда нарисовано, или Вы доберетесь 2x изображение, имеющее больше пикселей в его битовом массиве, чем Вы ожидаете.
Используя imageWithSize:flipped:drawingHandler:
метод гарантирует, что Вы получите корректные результаты под стандартным и высоким разрешением. Обработчик получения является блоком, который может быть вызван каждый раз, когда изображение нарисовано к, и на любом потоке происходит получение. Необходимо удостовериться, что любое состояние, к которому Вы получаете доступ в блоке, сделано ориентированным на многопотоковое исполнение способом.
Код в блоке должен быть тем же кодом, который Вы использовали бы между lockFocus
и unlockFocus
методы.
Обработайте динамические изменения в разрешении окна только, когда Вы будете должны
Прислушивание NSWindowDidChangeBackingPropertiesNotification
что-то только несколько приложений — прежде всего те приложения, специализирующиеся на видео или графической работе, и для которого согласование цветов и высококачественная точность рендеринга особенно важны — должен будет сделать.
Если Ваше приложение должно обработать изменения разрешения вручную, оно должно реагировать на уведомление NSWindowDidChangeBackingPropertiesNotification
когда разрешение запоминающего устройства данного NSWindow
объектные изменения. Если окно имеет делегата, отвечающего на windowDidChangeBackingProperties:
сообщение, его делегат получит уведомление через тот метод.
Ваше приложение получает NSWindowDidChangeBackingPropertiesNotification
каждый раз, когда происходит изменение разрешения или цветового пространства. Для определения который из измененных двух (или оба могли измениться) используйте эти ключи:
NSBackingPropertyOldScaleFactorKey
, который являетсяNSNumber
объектNSBackingPropertyOldColorSpaceKey
, который являетсяNSColorSpace
объект
Перечисление 3-4 показывает, как использовать ключи для получения отступающего масштаба и информации о цветовом пространстве из уведомления. В ответ на изменения в разрешении или цветовом пространстве, Вашей реализации windowDidChangeBackingProperties:
должен будет загрузить или генерировать побитово отображенные ресурсы изображения, надлежащие характеристикам нового окна. Вы, возможно, также должны были бы произвести чистку старых дубликатов, если они больше не необходимы.
Перечисление 3-4 , Реагирующее на изменения в свойствах поддержки окна
- (void)windowDidChangeBackingProperties:(NSNotification *)notification { |
NSWindow *theWindow = (NSWindow *)[notification object]; |
NSLog(@"windowDidChangeBackingProperties: window=%@", theWindow); |
CGFloat newBackingScaleFactor = [theWindow backingScaleFactor]; |
CGFloat oldBackingScaleFactor = [[[notification userInfo] |
objectForKey:@"NSBackingPropertyOldScaleFactorKey"] |
doubleValue]; |
if (newBackingScaleFactor != oldBackingScaleFactor) { |
NSLog(@"\tThe backing scale factor changed from %.1f -> %.1f", |
oldBackingScaleFactor, newBackingScaleFactor); |
} |
NSColorSpace *newColorSpace = [theWindow colorSpace]; |
NSColorSpace *oldColorSpace = [[notification userInfo] |
objectForKey:@"NSBackingPropertyOldColorSpaceKey"]; |
if (![newColorSpace isEqual:oldColorSpace]) { |
NSLog(@"\tThe color space changed from %@ -> %@", oldColorSpace, newColorSpace); |
} |
} |
Используйте NSReadPixel для доступа к экранным пикселям
Большую часть времени Вы не должны должны быть получать доступ к пикселям, но если Ваше приложение выполняет задачи, такие как обнаружение цвета пикселя, на который указывает пользователь, необходимо использовать NSReadPixel
функция.
Получите событие, содержащее пиксель, на который указывает пользователь.
Значение расположения будет в точках относительно фокусирующегося представления или окна.
Вызовите метод преобразования для получения расположения пикселя.
Внимание блокировки на представление.
Использовать
NSReadPixel
получить пиксель.Разблокируйте внимание на представление.
Получите значения компонента цвета.
Перечисление 3-5 показывает метод чтения пикселя полной выборки. Для дополнительных подробных данных см. Получение За пределами drawRect: в поле зрения Руководство по программированию.
Перечисление 3-5 читающий пиксель метод
- (void) examinePixelColor:(NSEvent *) theEvent |
{ |
NSPoint where; |
NSColor *pixelColor; |
CGFloat red, green, blue; |
where = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
// NSReadPixel pulls data out of the current focused graphics context, |
// so you must first call lockFocus. |
[self lockFocus]; |
pixelColor = NSReadPixel(where); |
// Always balance lockFocus with unlockFocus. |
[self unlockFocus]; |
red = [pixelColor redComponent]; |
green = [pixelColor greenComponent]; |
blue = [pixelColor blueComponent]; |
// Your code to do something with the color values |
} |
Скорректируйте параметры шрифта для обеспечения совместимости документа
В OS X v10.8, значение по умолчанию NSFontDefaultScreenFontSubstitutionEnabled
установка NO
. Эта установка определяет действительно ли текст APIs (такой как NSLayoutManager
, NSCell
, и NSStringDrawing
категории на NSString
и NSAttributedString
) замените экранными шрифтами при вычислении расположения и дисплея текста.
Несмотря на то, что экранная замена шрифтов больше не будет значением по умолчанию, использование экранного шрифта могло бы все еще быть надлежащим поддержке:
Совместимость с документами, создаваемыми с предыдущими версиями Вашего приложения. Различие в измерениях продвижения глифа между интегралом и значениями с плавающей точкой может вызвать изменение в текстовом расположении.
Вывод стиля простого текста фиксированной подачи — например, режим простого текста в текстовом Редактировании.
Для хранения OS X, v10.7 экранируют поведение замены шрифтов как значение по умолчанию, устанавливают NSUserDefaults
ключ NSFontDefaultScreenFontSubstitutionEnabled
к YES
.
Для поддержания экранного параметра шрифта на основе на документ указать NSUsesScreenFontsDocumentAttribute
как атрибут документа, когда Вы инициализируете приписанный строковый объект.
Помните, что кварцевые службы дисплея возвращают объекты CGImage, размерные в пикселях
Объекты CGImage всегда измеряются в пикселях; они не содержат метаданных относительно размера получения в точках. Таким образом, если Вы получаете доступ к экранным пикселям для создания изображения с помощью функций CGDisplayCreateImage
или CGDisplayCreateImageForRect
, необходимо будет знать, работает ли дисплей в стандарте - или режим с высокой разрешающей способностью для надлежащей интерпретации то, что означает размер пикселя. Если дисплей будет работать в режиме с высокой разрешающей способностью, то изображения будут иметь 2x запоминающее устройство.
Скорректируйте кварцевые образцы изображения для размещения высокого разрешения
Если Вы используете NSColor
класс для рисования изображения как образца OS X автоматически масштабирует образец изображения соответственно для разрешения устройства. При использовании Кварца для рисования образца изображения, необходимо будет скорректировать код, таким образом, образец нарисует правильно для высокого разрешения. Кварцевые образцы (CGPatternRef
) предложите управление всеми аспектами создания образца, такими как размер ячейки образца и располагающий с интервалами между образцами. Если Вам не нужен тот уровень управления, рассмотреть использование NSColor
вместо этого. Мало того, что система заботится о выборе правильно размерного изображения для Вас (как долго, поскольку Вы предоставляете стандарт - и версии с высокой разрешающей способностью), но код намного более просто. Сравните код в Перечислении 3-6 с этим в Перечислении 3-7. Каждый создает образец как показано на левой стороне Перечисления 3-7.
Перечисление 3-6 , Создающее образец с изображением с помощью класса NSColor
NSColor *myPattern = [NSColor colorWithPatternImage:[NSImage imageNamed:@"heart"]]; |
[myPattern setFill]; |
NSRectFill(myRect); |
Кварцевые образцы нарисованы в основном пространстве, что означает автоматическое масштабирование, выполняемое платформами при вовлечении окна, или представление не применяется к ним. Таким образом, когда Вы используете CGPatternRef
API для создания образца с помощью изображения необходимо составить разрешение окна, в которое Вы рисуете образец, в дополнение к обеспечению стандарта - и версии с высокой разрешающей способностью изображения. Если Вы не будете масштабировать образец изображения для высокого разрешения, то Ваш образец займет одну четверть места, это должно (как показано на рисунке 3-3), который является неправильным.
Перечисление 3-7 показывает, как создать образец изображения так, чтобы оно нарисовало правильно для высокого разрешения. drawRect:
метод передает масштаб рисующей образец функции. Та функция применяет масштаб до рисования образца. Также обратите внимание на то, что рисующий изображение обратный вызов использует imageNamed:
метод для загрузки надлежащей версии изображения.
Перечисление 3-7 , Создающее образец с изображением с помощью Кварца
@implementation PatternView |
#define PATTERN_CELL_WIDTH 32 |
#define PATTERN_CELL_HEIGHT 32 |
- (id)initWithFrame:(NSRect)frame |
{ |
self = [super initWithFrame:frame]; |
if (self) { |
// Initialization code here. |
} |
return self; |
} |
void MyDrawImage (void *info,CGContextRef myContext) |
{ |
// Provide two versions of the image—standard and @2x |
NSImage *myImage = [NSImage imageNamed:@"heart_32"]; |
[myImage drawAtPoint:NSMakePoint(0.0,0.0) |
fromRect:NSMakeRect(0.0,0.0, PATTERN_CELL_WIDTH, PATTERN_CELL_HEIGHT) |
operation:NSCompositeSourceOver |
fraction:1.0]; |
} |
void MyDrawPatternWithImage (CGContextRef myContext, CGRect rect, CGFloat scale) |
{ |
CGPatternRef pattern; |
CGColorSpaceRef patternSpace; |
CGFloat alpha = 1.0; |
static const CGPatternCallbacks callbacks = {0, &MyDrawImage, NULL}; |
patternSpace = CGColorSpaceCreatePattern (NULL); |
CGContextSetFillColorSpace (myContext, patternSpace); |
CGColorSpaceRelease (patternSpace); |
pattern = CGPatternCreate (NULL, |
CGRectMake (0, 0, PATTERN_CELL_WIDTH, |
PATTERN_CELL_HEIGHT), |
CGAffineTransformMake (1/scale, 0, 0, |
1/scale, 0, 0), |
PATTERN_CELL_WIDTH, |
PATTERN_CELL_HEIGHT, |
kCGPatternTilingConstantSpacingMinimalDistortion, |
true, |
&callbacks); |
CGContextSetFillPattern (myContext, pattern, &alpha); |
CGPatternRelease (pattern); |
CGContextFillRect (myContext, rect); |
} |
- (void)drawRect:(NSRect)dirtyRect |
{ |
NSGraphicsContext *nsctx = [NSGraphicsContext currentContext]; |
CGContextRef cgctx = (CGContextRef)[nsctx graphicsPort]; |
NSRect bounds = [self bounds]; |
NSRect backingBounds = [self convertRectToBacking:bounds]; |
CGFloat scale = backingBounds.size.width/bounds.size.width; |
// Draw the pattern into the view bounds |
MyDrawPatternWithImage(cgctx, bounds, scale); |
} |
@end |
Используйте Изображение Платформа I/O для Упаковки Во время выполнения Значков
Если Ваши поддержки приложений редактирующие или создающие изображения значка, Вы, возможно, должны были бы упаковать значки программно с помощью Изображения платформа I/O. Иначе, необходимо выполнить простые процедуры, обрисованные в общих чертах в, Обеспечивают Версии С высокой разрешающей способностью Всех Ресурсов Графики Приложения для упаковочных значков.
Создайте ряд изображений, представляющих каждый размер ресурса, поставляющего стандарта и @2x разрешений для каждого.
Создайте место назначения изображения, которое достаточно крупно для размещения числа изображений в массиве:
CGImageDestinationRef destination =
CGImageDestinationCreateWithURL(myURL, kUTTypeAppleICNS,
myNumberOfImages, NULL);
где
myURL
URL для записи данных в.Создайте словарь для каждого изображения и добавьте пары ключ/значение для высоты точек на дюйм изображения и ширины.
Точки на дюйм изображения должны отразить разрешение. Т.е. версия с высокой разрешающей способностью должна иметь дважды точки на дюйм как версию стандартного разрешения.
NSDictionary* properties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithUnsignedInteger:imageDPI],
kCGImagePropertyDPIHeight,
[NSNumber numberWithUnsignedInteger:imageDPI],
kCGImagePropertyDPIWidth,
nil];
Добавьте каждое изображение и его словарь свойства месту назначения изображения.
CGImageDestinationAddImage(destination,
oneOfMyImages, (CFDictionaryRef)properties);
Завершите место назначения изображения.
Вы не будете в состоянии добавить больше данные к месту назначения после выполнения этого шага.
BOOL success = CGImageDestinationFinalize(destination);
Для получения базовых представлений от файла, содержащего многократные версии ресурса изображения используйте Изображение платформа I/O для создания источника изображения. Затем выполните итерации через источник изображения с помощью функции CGImageSourceCreateImageAtIndex
получать каждое изображение. Для получения дополнительной информации посмотрите Ссылку CGImageSource и Изображение Руководство по программированию I/O.
После извлечения отдельного изображения можно нарисовать его с помощью одного из методов NSImage
класс.