Базовое графическое получение уровня

Объекты CGLayer (CGLayerRef тип данных), позволяют Вашему приложению использовать уровни для рисования.

Уровни подходят для следующего:

Рисунок 12-1  , Неоднократно крася то же изображение бабочки
Repeatedly painting the same butterfly image

Объекты CGLayer и слои прозрачности параллельны объектам CGPath и путям, создаваемым функциями CGContext. В случае CGLayer или объекта CGPath, Вы красите абстрактному месту назначения и можете тогда позже нарисовать полное рисование другому месту назначения, такому как дисплей или PDF. Когда Вы красите к слою прозрачности или используете функции CGContext, рисующие пути, Вы рисуете непосредственно месту назначения, представленному графическим контекстом. Нет никакого промежуточного абстрактного места назначения для сборки рисования.

Как работает рисование уровня

Уровень, представленный CGLayerRef тип данных, спроектирован для оптимальной производительности. Когда возможно, Кварц кэширует объект CGLayer использование механизма, надлежащего типу Кварцевого контекста графики, с которым это связано. Например, графический контекст, связанный с видеокартой, мог бы кэшировать уровень на видеокарте, делающей рисование содержания, это находится в уровне намного быстрее, чем рендеринг подобного изображения, это создается из контекста растрового изображения. Поэтому уровень обычно является лучшим выбором для внеэкранного получения, чем контекст растрового изображения.

Все Кварцевые функции рисования рисуют к графическому контексту. Графический контекст обеспечивает абстракцию места назначения, освобождая Вас от подробных данных места назначения, таких как ее разрешение. Вы работаете в пространстве пользователя, и Кварц выполняет необходимые трансформации для рендеринга получения правильно месту назначения. При использовании объекта CGLayer для рисования Вы также рисуете к графическому контексту. Рисунок 12-1 иллюстрирует необходимые шаги для получения уровня.

  Получение Уровня рисунка 12-2
CGLayer drawing

Все получение уровня запускается с графического контекста, из которого Вы создаете объект CGLayer использование функции CGLayerCreateWithContext. Графический контекст, используемый для создания объекта CGLayer, обычно является контекстом графики окна. Кварц создает уровень так, чтобы он имел все характеристики графического контекста — его разрешение, цветовое пространство и настройки состояния графики. Если Вы не хотите использовать размер графического контекста, можно обеспечить размер для уровня. На рисунке 12-2 левая сторона показывает, что графический контекст раньше создавал уровень. Серая часть поля на правой стороне, маркированном объекте CGLayer, представляет недавно создаваемый уровень.

Прежде чем можно будет нарисовать к уровню, необходимо получить графический контекст, это связано с уровнем путем вызывания функции CGLayerGetContext. Этот графический контекст является той же разновидностью, как графический контекст раньше создавал уровень. Пока графический контекст, используемый для создания уровня, является контекстом графики окна, тогда графический контекст CGLayer кэшируется к GPU если вообще возможный. Белая часть поля на правой стороне рисунка 12-2 представляет недавно создаваемый контекст графики уровня.

Вы рисуете к графическому контексту уровня, как Вы нарисовали бы к любому графическому контексту, передав графический контекст уровня функции получения. Рисунок 12-2 показывает, что лист формирует нарисованный к контексту уровня.

Когда Вы готовы использовать содержание уровня, можно вызвать функции CGContextDrawLayerInRect или CGContextDrawLayerAtPoint, вовлекать уровень в графический контекст. Обычно Вы нарисовали бы к тому же графическому контексту, что Вы раньше создавали расположенный на слое объект, но Вы не обязаны. Можно нарисовать уровень к любому графическому контексту, имея в виду, что получение уровня имеет характеристики графического контекста, используемого для создания расположенного на слое объекта, который мог наложить определенные ограничения (производительность или разрешение, например). Например, уровень, связанный с экраном, может кэшироваться в видеооборудовании. Если целевой контекст является печатью или контекстом PDF, он, возможно, должен быть выбран от аппаратного обеспечения машинной графики до памяти, приводящей к низкой производительности.

Рисунок 12-2 показывает содержание уровня — лист — рисовавшийся неоднократно к графическому контексту раньше создавал расположенный на слое объект. Можно снова использовать получение, это находится в уровне так много раз, как Вы хотели бы прежде, чем выпустить объект CGLayer.

Рисование с уровнем

Необходимо выполнить задачи, описанные в следующем разделе для рисования использования объекта CGLayer:

  1. Создайте объект CGLayer, инициализированный с существующим графическим контекстом

  2. Получите графический контекст для уровня

  3. Нарисуйте к графическому контексту CGLayer

  4. Нарисуйте уровень к целевому графическому контексту

Посмотрите Пример: Используя Многократные Объекты CGLayer Нарисовать Флаг для подробного примера кода.

Создайте объект CGLayer, инициализированный с существующим графическим контекстом

Функция CGLayerCreateWithContext возвращает уровень, инициализирующийся с существующим графическим контекстом. Уровень наследовал все характеристики графического контекста, включая цветовое пространство, размер, разрешение и формат пикселя. Позже, когда Вы рисуете уровень месту назначения, Кварц автоматически окрашивают соответствия уровнем к целевому контексту.

Функция CGLayerCreateWithContext берет три параметра:

  • Графический контекст для создания уровня из. Обычно Вы передаете контекст графики окна так, чтобы можно было позже нарисовать уровень на экране.

  • Размер уровня относительно графического контекста. Уровень может быть тем же размером как графический контекст или меньший. Если необходимо получить размер уровня позже, можно вызвать функцию CGLayerGetSize.

  • Вспомогательный словарь. Этот параметр в настоящее время не использован, так передача NULL.

Получите графический контекст для уровня

Кварц всегда рисует к графическому контексту. Теперь, когда у Вас есть уровень, необходимо создать графический контекст, связанный с уровнем. Что-либо Вы вовлекаете контекст графики уровня, является частью уровня.

Функция CGLayerGetContext берет уровень в качестве параметра и возвращает графический контекст, связанный с уровнем.

Нарисуйте к графическому контексту CGLayer

После получения графического контекста, связанного с уровнем можно выполнить любое получение, которое Вы хотели бы к контексту графики уровня. Можно открыть файл PDF или файл образа и нарисовать содержание файла к уровню. Можно использовать любой Кварц 2D функции для рисования прямоугольников, строк и других примитивов получения. Рисунок 12-3 показывает пример рисования прямоугольников и строк к уровню.

Рисунок 12-3  уровень, содержащий два прямоугольника и серию строк
A layer that contains two rectangles and a series of lines

Например, для рисования заполненного прямоугольника к графическому контексту CGLayer Вы вызываете функцию CGContextFillRect, предоставление графического контекста Вы получили из функции CGLayerGetContext. Если называют графический контекст myLayerContext, вызов функции похож на это:

CGContextFillRect (myLayerContext, myRect)

Нарисуйте уровень к целевому графическому контексту

Когда Вы готовы нарисовать уровень к его целевому графическому контексту, можно использовать любую из следующих функций:

  • CGContextDrawLayerInRect, который рисует уровень к графическому контексту в указанном прямоугольнике.

  • CGContextDrawLayerAtPoint, который рисует уровень к графическому контексту в указанной точке.

Обычно целевой графический контекст, который Вы предоставляете, является контекстом графики окна, и это - тот же графический контекст, который Вы используете для создания уровня. Рисунок 12-4 показывает результат повторного рисования получения уровня, показанного на рисунке 12-3. Для достижения шаблонного эффекта Вы вызываете любую из функций рисования уровня неоднократно —CGContextDrawLayerAtPoint или CGContextDrawLayerInRect— изменение смещения каждый раз. Например, можно вызвать функцию CGContextTranslateCTM для изменения источника координатного пространства каждый раз, Вы рисуете уровень.

Рисунок 12-4  , Получающий уровень неоднократно
Drawing a layer repeatedly

Пример: Используя многократный CGLayer возражает для рисования флага

Этот раздел показывает, как использовать два объекта CGLayer нарисовать флаг, показанный на рисунке 12-5 на экране. Сначала Вы будете видеть, как сократить флаг до простых примитивов получения, тогда Вы будете смотреть на код, должен был выполнить получение.

Рисунок 12-5  результат использования уровней для рисования флага США
The result of using layers to draw the United States flag

С точки зрения рисования его на экране, флаг имеет три части:

Код на рисунке 12-2 производит вывод, показанный на рисунке 12-5. Подробное объяснение каждой пронумерованной строки кода появляется после перечисления. Перечисление довольно долго, таким образом, Вы могли бы хотеть распечатать объяснение так, чтобы можно было считать его, поскольку Вы смотрите на код. myDrawFlag подпрограмму вызывают из приложения Какао. Приложение передает контекст графики окна и прямоугольник, указывающий размер представления, связанного с контекстом графики окна.

  Код перечисления 12-1, использующий уровни для рисования флага

void myDrawFlag (CGContextRef context, CGRect* contextRect)
{
    int          i, j,
                 num_six_star_rows = 5,
                 num_five_star_rows = 4;
    CGFloat      start_x = 5.0,// 1
                 start_y = 108.0,// 2
                 red_stripe_spacing = 34.0,// 3
                 h_spacing = 26.0,// 4
                 v_spacing = 22.0;// 5
    CGContextRef myLayerContext1,
                 myLayerContext2;
    CGLayerRef   stripeLayer,
                 starLayer;
    CGRect       myBoundingBox,// 6
                 stripeRect,
                 starField;
 // ***** Setting up the primitives *****
    const CGPoint myStarPoints[] = {{ 5, 5},   {10, 15},// 7
                                    {10, 15},  {15, 5},
                                    {15, 5},   {2.5, 11},
                                    {2.5, 11}, {16.5, 11},
                                    {16.5, 11},{5, 5}};
 
    stripeRect  = CGRectMake (0, 0, 400, 17); // stripe// 8
    starField  =  CGRectMake (0, 102, 160, 119); // star field// 9
 
    myBoundingBox = CGRectMake (0, 0, contextRect->size.width, // 10
                                      contextRect->size.height);
 
     // ***** Creating layers and drawing to them *****
    stripeLayer = CGLayerCreateWithContext (context, // 11
                            stripeRect.size, NULL);
    myLayerContext1 = CGLayerGetContext (stripeLayer);// 12
 
    CGContextSetRGBFillColor (myLayerContext1, 1, 0 , 0, 1);// 13
    CGContextFillRect (myLayerContext1, stripeRect);// 14
 
    starLayer = CGLayerCreateWithContext (context,
                            starField.size, NULL);// 15
    myLayerContext2 = CGLayerGetContext (starLayer);// 16
    CGContextSetRGBFillColor (myLayerContext2, 1.0, 1.0, 1.0, 1);// 17
    CGContextAddLines (myLayerContext2, myStarPoints, 10);// 18
    CGContextFillPath (myLayerContext2);    // 19
 
     // ***** Drawing to the window graphics context *****
    CGContextSaveGState(context);    // 20
    for (i=0; i< 7;  i++)   // 21
    {
        CGContextDrawLayerAtPoint (context, CGPointZero, stripeLayer);// 22
        CGContextTranslateCTM (context, 0.0, red_stripe_spacing);// 23
    }
    CGContextRestoreGState(context);// 24
 
    CGContextSetRGBFillColor (context, 0, 0, 0.329, 1.0);// 25
    CGContextFillRect (context, starField);// 26
 
    CGContextSaveGState (context);              // 27
    CGContextTranslateCTM (context, start_x, start_y);      // 28
    for (j=0; j< num_six_star_rows;  j++)   // 29
    {
        for (i=0; i< 6;  i++)
        {
            CGContextDrawLayerAtPoint (context,CGPointZero,
                                            starLayer);// 30
            CGContextTranslateCTM (context, h_spacing, 0);// 31
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing); // 32
    }
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, start_x + h_spacing/2, // 33
                                 start_y + v_spacing/2);
    for (j=0; j< num_five_star_rows;  j++)  // 34
    {
        for (i=0; i< 5;  i++)
        {
        CGContextDrawLayerAtPoint (context, CGPointZero,
                            starLayer);// 35
            CGContextTranslateCTM (context, h_spacing, 0);// 36
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing);// 37
    }
    CGContextRestoreGState(context);
 
    CGLayerRelease(stripeLayer);// 38
    CGLayerRelease(starLayer);        // 39
}

Вот то, что делает код:

  1. Объявляет переменную для горизонтального расположения первой звезды.

  2. Объявляет переменную для вертикального расположения первой звезды.

  3. Объявляет переменную для интервала между красными дорожками на флаге.

  4. Объявляет переменную для пространства по горизонтали между звездами на флаге.

  5. Объявляет переменную для пространства по вертикали между звездами на флаге.

  6. Объявляет прямоугольники, указывающие, где нарисовать флаг к (ограничительной рамке), уровню дорожки и звездообразному полю.

  7. Объявляет массив точек, указывающих строки, прослеживающие одну звезду.

  8. Создает прямоугольник, который является формой единственной дорожки.

  9. Создает прямоугольник, который является формой звездообразного поля.

  10. Создает ограничительную рамку, которая является тем же размером, как контекст графики окна передал myDrawFlag подпрограмма.

  11. Создает уровень, инициализирующийся с контекстом графики окна, переданным myDrawFlag подпрограмма.

  12. Связали графический контекст с тем уровнем. Вы будете использовать этот уровень для получения дорожки.

  13. Устанавливает цвет заливки в непрозрачный красный для графического контекста, связанного с уровнем дорожки.

  14. Заполняет прямоугольник, представляющий одну красную дорожку.

  15. Создает другой уровень, инициализирующийся с контекстом графики окна, переданным myDrawFlag подпрограмма.

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

  17. Устанавливает цвет заливки в непрозрачного белого для графического контекста, связанного со звездообразным уровнем.

  18. Добавляют эти 10 строк, определенных myStarPoints выстройте к контексту, связанному со звездообразным уровнем.

  19. Заполняет путь, состоящий из этих 10 строк, которые Вы просто добавили.

  20. Сохраняет состояние графики контекста графики окон. Необходимо сделать это, потому что Вы будете неоднократно рисовать ту же дорожку, но в различных расположениях.

  21. Устанавливает цикл, выполняющий итерации 7 раз, один раз для каждой красной дорожки на флаге.

  22. Рисует уровень дорожки (который состоит из единственной красной дорожки).

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

  24. Восстанавливает состояние графики к тому, что, был до рисования дорожек.

  25. Устанавливает цвет заливки в надлежащий оттенок синего цвета для звездообразного поля. Обратите внимание на то, что этот цвет имеет непрозрачность 1,0. Несмотря на то, что все цвета в этом примере непрозрачны, они не должны быть. Можно создать хорошие эффекты с многоуровневым получением при помощи частично прозрачных цветов. Вспомните, что альфа-значение 0,0 указывает прозрачный цвет.

  26. Заполняет звездообразный полевой прямоугольник синим. Вы рисуете этот прямоугольник непосредственно к контексту графики окна. Не используйте уровни при рисовании чего-то только один раз.

  27. Сохраняет состояние графики для контекста графики окна, потому что Вы будете преобразовывать CTM для расположения звезд должным образом.

  28. Переводит CTM так, чтобы источник нашелся в звездообразном поле, расположенном для первой звезды (левая сторона) в первом (нижняя часть) строка.

  29. Это и следующее для цикла устанавливают код для повторного рисования звездообразного уровня так пять нечетных строк на флаге, каждый содержит шесть звезд.

  30. Рисует звездообразный уровень к контексту графики окна. Вспомните, что звездообразный уровень содержит одну белую звезду.

  31. Располагает CTM так, чтобы источник был перемещен вправо в подготовке к рисованию следующей звезды.

  32. Располагает CTM так, чтобы источник был перемещен вверх в подготовке к рисованию следующей строки звезд.

  33. Переводит CTM так, чтобы источник нашелся в звездообразном поле, расположенном для первой звезды (левая сторона) во второй строке от нижней части. Обратите внимание на то, что ровные строки смещаются относительно нечетных строк.

  34. Это и следующее для цикла устанавливают код для повторного рисования звездообразного уровня так четыре даже строки на флаге, каждый содержит пять звезд.

  35. Рисует звездообразный уровень к контексту графики окна.

  36. Располагает CTM так, чтобы источник был перемещен вправо в подготовке к рисованию следующей звезды.

  37. Располагает CTM так, чтобы источник снизился и налево в подготовке к рисованию следующей строки звезд.

  38. Выпускает уровень дорожки.

  39. Выпускает звездообразный уровень.