Core Graphics — фреймворк 2D-рендеринга от Apple, входящий в состав Core Foundation и доступный на iOS, macOS, tvOS и watchOS. Он предоставляет низкоуровневый C-API для работы с векторной и растровой графикой, включая отрисовку контуров, градиентов, теней, изображений и текста. Core Graphics служит основой для UIKit, SwiftUI и AppKit. По данным Apple Developer Documentation, 2026, фреймворк используется более чем в 90% iOS-приложений, так как любой видимый элемент проходит через Core Graphics или его аппаратный аналог.
Главное
Core Graphics (также известный как Quartz 2D) — это фреймворк, реализующий 2D-графический движок Apple. Он основан на портативной графической библиотеке Quartz и использует модель рисования на основе страницы (page-based), где каждое действие — это команда в последовательности, напоминающей рисование на бумаге. Core Graphics поддерживает антиалиасинг, прозрачность (alpha compositing) и цветовые пространства ICC.
Архитектура Core Graphics построена вокруг графического контекста (CGContext), который инкапсулирует целевое устройство вывода — экран, принтер, PDF-документ или растровый буфер. Контекст управляет текущими настройками: цветом, толщиной линии, трансформацией, областью отсечения и шрифтами. Такой подход обеспечивает единообразный API для разных устройств вывода без изменения кода рисования.
Core Graphics работает преимущественно на CPU, используя векторную модель (resolution-independent). Это означает, что линии и кривые растеризуются с текущим разрешением устройства при отрисовке. В отличие от Metal, Core Graphics не требует явного управления GPU-ресурсами — всю оптимизацию берёт на себя система. Для большинства 2D-задач (графика, диаграммы, кастомные элементы UI) производительности Core Graphics достаточно для поддержания 60 FPS.
Core Graphics включает около 50 базовых типов (opaque types), каждый из которых отвечает за определённую функциональность. Все типы следуют правилам управления памятью Core Foundation: создаются через функции с Create в названии, требуют вызова CGRelease, и не являются ARC-совместимыми в Objective-C (однако Swift автоматически управляет памятью через аннотации CF_RETURNS_RETAINED).
CGContext — контекст рисования, центральный тип фреймворка. CGPath — неизменяемый векторный контур. CGColor — цвет с указанием цветового пространства. CGGradient — градиентная заливка. CGImage — растровое изображение. CGLayer — оптимизированный оффлайн-буфер для повторяющейся отрисовки. CGDataProvider — источник данных для изображений. CGColorSpace — цветовое пространство (sRGB, Display P3, Gray).
Каждый тип спроектирован для минимального оверхеда: CGPath может кэшироваться и переиспользоваться между разными контекстами, CGColor преобразуется в аппаратное представление GPU при передаче, CGLayer хранит предварительно растеризованное содержимое. Такая архитектура позволяет Core Graphics эффективно работать как в простых UI-задачах, так и в профессиональных графических редакторах.
| Тип | Назначение | Управление памятью |
|---|---|---|
| CGContext | Графический контекст | CFRelease или автоматическое в Swift |
| CGPath | Векторный контур | CFRelease (неизменяемый) |
| CGColor | Цвет в цветовом пространстве | CFRelease или CGColorCreate |
| CGImage | Растровое изображение | CFRelease (после создания) |
| CGLayer | Оффлайн-буфер | CFRelease или CGLayerCreate |
CGPath — неизменяемый объект, описывающий последовательность геометрических сегментов: прямых линий, кривых Безье, дуг и замыканий. В отличие от UIBezierPath, CGPath не содержит методов рисования — он только хранит геометрию. Для отрисовки CGPath добавляется в контекст (CGContextAddPath) и затем рисуется через strokePath или fillPath. Неизменяемость гарантирует потокобезопасность и возможность кэширования.
CGPathCreateMutable создаёт изменяемый путь (CGMutablePathRef) для поэтапного построения. После финальной сборки он превращается в неизменяемый CGPathRef. Apple рекомендует минимизировать количество точек в CGPath — слишком сложные контуры (более 1000 сегментов) замедляют растеризацию. Для оптимизации используйте CGPathCreateCopyBySimplifyingPath, который удаляет избыточные коллинеарные точки.
Для анимации формы между двумя CGPath можно использовать CABasicAnimation на свойстве path CAShapeLayer. Ограничение: оба CGPath должны иметь одинаковое количество сегментов (controls points). Функция CGPathApply позволяет обойти все элементы пути и сравнить их структуру. Если сегменты не совпадают, анимация будет дёрганой — в этом случае используйте CADisplayLink для ручной интерполяции точек.
// create mutable path
let mutablePath = CGMutablePath()
mutablePath.moveTo(to: CGPoint(x: 0, y: 0))
mutablePath.addLine(to: CGPoint(x: 100, y: 0))
mutablePath.addLine(to: CGPoint(x: 100, y: 100))
mutablePath.closeSubpath()
// convert to immutable for safe caching
let immutablePath: CGPath = mutablePath
CATransaction.perform {
shapeLayer.path = immutablePath
}
CGGradient — объект, определяющий плавный переход между двумя или более цветами вдоль прямой линии (линейный градиент) или от центра к краям (радиальный градиент). CGGradient создаётся с указанием цветового пространства, массива CGColorRef и массива позиций остановок от 0.0 до 1.0. После создания градиент можно использовать многократно в разных контекстах.
CGShading — более мощный механизм, позволяющий задавать функцию изменения цвета вдоль пути. В отличие от CGGradient, который работает с фиксированным набором цветов, CGShading использует callback-функцию (CGFunctionRef), вычисляющую цвет в каждой точке. Это позволяет создавать сложные градиенты с нелинейными переходами и составными цветовыми схемами.
Для отрисовки градиента внутри фигуры необходим clip на контур этой фигуры. Порядок: добавить путь в контекст, вызвать CGContextClip, затем нарисовать градиент. Без clip градиент заполняет весь контекст целиком. В iOS рекомендуется использовать CGGradient как более простой и производительный вариант — CGShading оправдан только для нестандартных функций изменения цвета.
func drawGradient(ctx: CGContext, rect: CGRect) {
let colors = [UIColor.red.cgColor, UIColor.blue.cgColor] as CFArray
guard let gradient = CGGradient(
colorsSpace: CGColorSpaceCreateDeviceRGB(),
colors: colors,
locations: [0.0, 1.0]
) else { return }
ctx.saveGState()
ctx.addEllipse(in: rect)
ctx.clip()
ctx.drawLinearGradient(
gradient,
start: CGPoint(x: rect.midX, y: rect.minY),
end: CGPoint(x: rect.midX, y: rect.maxY),
options: []
)
ctx.restoreGState()
}
CGImage — растровое изображение в Core Graphics, которое может быть загружено из файла, создано программно или получено из UIImage. CGImage содержит пиксельные данные, информацию о цветовом пространстве, размере, бит-глубине и расположении данных. В отличие от UIImage, CGImage не управляет масштабированием для Retina — эту ответственность берёт на себя разработчик через параметр scale.
CGLayer — оффлайн-буфер для предварительной растеризации статического содержимого. Если один и тот же набор графических команд отрисовывается многократно (например, паттерн фона), CGLayer растеризует его один раз и затем просто копирует в контекст. По данным Apple, использование CGLayer может ускорить повторяющуюся отрисовку в 2–5 раз на CPU и до 10 раз при аппаратном ускорении.
Для загрузки изображений используйте CGImageSource — мощный API для чтения метаданных, миниатюр и отдельных кадров из GIF/APNG. CGImageSource позволяет загружать изображение прогрессивно и получать только необходимые фрагменты. При работе с большими изображениями (превышающими размер экрана) рекомендуется создавать CGImageSource с опцией кэширования на диске и использовать CGImageSourceCreateThumbnailAtIndex для отображения уменьшенной версии.
func createLayer(ctx: CGContext, size: CGSize) -> CGLayer? {
guard let layer = CGLayer(ctx, size: size, auxiliaryInfo: nil) else { return nil }
let layerCtx = layer.context !
// draw once
layerCtx.setFillColor(UIColor.lightGray.cgColor)
layerCtx.addEllipse(in: CGRect(origin: .zero, size: size))
layerCtx.fillPath()
return layer
}
// usage in draw()
for i in 0..<20 {
ctx.draw(layer, at: CGPoint(x: CGFloat(i) * 30, y: 0))
}
Разработаем кастомное View для отображения водяного знака на изображении с использованием Core Graphics. Водяной знак включает полупрозрачный текст и векторный логотип, наложенные поверх исходного изображения. Код демонстрирует работу с CGContext, CGImage, текстом и прозрачностью в одном контексте.
class WatermarkView: UIView {
private let watermarkText = "IT Sectr"
private let watermarkOpacity: CGFloat = 0.3
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// draw background image
UIImage(named: "background")?.draw(in: rect)
// configure watermark transparency
ctx.saveGState()
ctx.translateBy(x: rect.midX, y: rect.midY)
ctx.rotate(by: -.pi / 6)
// semi-transparent text
let attributes: NSAttributedString.Attributes = [
.font: UIFont.boldSystemFont(ofSize: 48),
.foregroundColor: UIColor.white.withAlphaComponent(watermarkOpacity)
]
let textSize = watermarkText.size(withAttributes: attributes)
watermarkText.draw(
at: CGPoint(x: -textSize.width / 2, y: -textSize.height / 2),
withAttributes: attributes
)
// vector icon (circle with cross) below text
ctx.setStrokeColor(UIColor.white.withAlphaComponent(watermarkOpacity).cgColor)
ctx.setLineWidth(3)
ctx.addEllipse(in: CGRect(x: -25, y: -75, width: 50, height: 50))
ctx.strokePath()
ctx.moveTo(x: -15, y: -50)
ctx.addLineTo(x: 15, y: -50)
ctx.moveTo(x: 0, y: -65)
ctx.addLineTo(x: 0, y: -35)
ctx.strokePath()
ctx.restoreGState()
}
}
В коде использованы ключевые возможности Core Graphics: saveGState/restoreGState для изоляции эффектов водяного знака от фона, translateBy и rotate для позиционирования и поворота, полупрозрачный текст через withAlphaComponent и векторная иконка через addEllipse и addLineTo. Весь водяной знак рисуется как единая композиция после фонового изображения.
При создании водяных знаков для фотографий в продакшене важно учитывать производительность. Если изображение больше экрана, перед наложением водяного знака уменьшите его через CGImageSourceCreateThumbnailAtIndex. Core Graphics обрабатывает все операции на CPU — для пакетной обработки десятков изображений используйте фоновую очередь и CGBitmapContext для избежания блокировки UI.
Часто задаваемые вопросы
UIKit — высокоуровневый фреймворк UI, использующий Core Graphics внутри себя для отрисовки. Core Graphics — низкоуровневый C-API для 2D-графики. UIKit удобнее для стандартных элементов, Core Graphics даёт полный контроль над каждым пикселем.
Core Graphics подходит для статической 2D-графики, диаграмм и кастомных UI-элементов. Metal — для 3D-графики, сложных анимаций и обработки больших массивов пикселей с GPU-ускорением. Для 95% UI-задач достаточно Core Graphics.
Используйте CGImageSource для загрузки миниатюр через createThumbnailAtIndex вместо полной загрузки. Для отображения больших изображений создавайте CGImage с downsample-опцией. Освобождайте CGImage через CGImageRelease когда он больше не нужен.
Да, Core Graphics включает полноценную поддержку PDF через CGPDFDocument для чтения и CGPDFContext для создания PDF-документов. Можно рисовать любой CGContext-контент прямо в PDF-страницу с сохранением векторов.
Core Graphics автоматически использует разрешение устройства при отрисовке на экране. Для оффлайн-контекстов используйте UIGraphicsBeginImageContextWithOptions с параметром scale = 0 (системный масштаб) или явно укажите 2.0/3.0 для Retina/Retina HD.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также