Усовершенствованные методы оптимизации

Эта глава дает представление для специализированных задач, которые не выполняет каждое приложение. Если Ваш 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.

Рисунок 3-1  , Разрешающий поддержку с высокой разрешающей способностью для представления OpenGL

Установите область просмотра для поддержки высокого разрешения

Размерности области просмотра находятся в пикселях относительно поверхности 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. Текст выглядит одинаково на обоих без любой дополнительной работы с Вашей стороны.

Рисунок 3-2  текстовое наложение масштабируется автоматически для (оставленного) стандартного разрешения и высокое разрешение (право)
bullet
Устанавливать поддержанное уровнем представление для содержания OpenGL
  1. Установите wantsLayer свойство Вашего NSOpenGLView подкласс к YES.

    Включение wantsLayer свойство NSOpenGLView объект активирует поддержанный уровнем рендеринг представления OpenGL. Рисование поддержанного уровнем представления OpenGL продолжается главным образом обычно посредством представления drawRect: метод. Поддержанный уровнем режим рендеринга использует свое собственное NSOpenGLContext объект, который отличен от NSOpenGLContext то, что использование представления для того, чтобы подойти к концу не уровень поддержало режим.

    AppKit автоматически создает этот контекст и присваивает его представлению путем вызова setOpenGLContext: метод. Представление openGLContext средство доступа возвратит поддержанный уровнем контекст OpenGL (а не не уровень поддержал контекст), в то время как представление работает в поддержанном уровнем режиме.

  2. Создайте содержание уровня или как файл XIB или программно.

    Средства управления, показанные на рисунке 3-2, создавались в файле XIB путем разделения на подклассы NSBox и использование статического текста со множеством стандартных средств управления. Используя этот подход позволяет NSBox подкласс для игнорирования событий от нажатия мыши, все еще позволяя пользователю взаимодействовать с содержанием OpenGL.

  3. Добавьте уровень к представлению 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 объекты, Вы ответственны за:

Сделать обновление уровней, которыми Вы управляете проще, реализация 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, что необходимо удостовериться, что Вы включаете в свой собственный код.

Перечисление 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 каждый раз, когда происходит изменение разрешения или цветового пространства. Для определения который из измененных двух (или оба могли измениться) используйте эти ключи:

Перечисление 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 функция.

bullet
Исследовать пиксель непосредственно
  1. Получите событие, содержащее пиксель, на который указывает пользователь.

    Значение расположения будет в точках относительно фокусирующегося представления или окна.

  2. Вызовите метод преобразования для получения расположения пикселя.

  3. Внимание блокировки на представление.

  4. Использовать NSReadPixel получить пиксель.

  5. Разблокируйте внимание на представление.

  6. Получите значения компонента цвета.

Перечисление 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-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. Иначе, необходимо выполнить простые процедуры, обрисованные в общих чертах в, Обеспечивают Версии С высокой разрешающей способностью Всех Ресурсов Графики Приложения для упаковочных значков.

bullet
Программно упаковывать ряд значков в один источник
  1. Создайте ряд изображений, представляющих каждый размер ресурса, поставляющего стандарта и @2x разрешений для каждого.

  2. Создайте место назначения изображения, которое достаточно крупно для размещения числа изображений в массиве:

    CGImageDestinationRef destination =
          CGImageDestinationCreateWithURL(myURL, kUTTypeAppleICNS,
                                          myNumberOfImages, NULL);

    где myURL URL для записи данных в.

  3. Создайте словарь для каждого изображения и добавьте пары ключ/значение для высоты точек на дюйм изображения и ширины.

    Точки на дюйм изображения должны отразить разрешение. Т.е. версия с высокой разрешающей способностью должна иметь дважды точки на дюйм как версию стандартного разрешения.

    NSDictionary* properties = [NSDictionary dictionaryWithObjectsAndKeys:
                               [NSNumber numberWithUnsignedInteger:imageDPI],
                                           kCGImagePropertyDPIHeight,
                               [NSNumber numberWithUnsignedInteger:imageDPI],
                                           kCGImagePropertyDPIWidth,
                               nil];
  4. Добавьте каждое изображение и его словарь свойства месту назначения изображения.

    CGImageDestinationAddImage(destination,
                        oneOfMyImages, (CFDictionaryRef)properties);
  5. Завершите место назначения изображения.

    Вы не будете в состоянии добавить больше данные к месту назначения после выполнения этого шага.

    BOOL success = CGImageDestinationFinalize(destination);

Для получения базовых представлений от файла, содержащего многократные версии ресурса изображения используйте Изображение платформа I/O для создания источника изображения. Затем выполните итерации через источник изображения с помощью функции CGImageSourceCreateImageAtIndex получать каждое изображение. Для получения дополнительной информации посмотрите Ссылку CGImageSource и Изображение Руководство по программированию I/O.

После извлечения отдельного изображения можно нарисовать его с помощью одного из методов NSImage класс.