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 за ръчна интерполация на точките.
// създаване на променлив път
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()
// преобразуване в неизменим за безопасно кеширане
let immutablePath: CGPath = mutablePath
CATransaction.perform {
shapeLayer.path = immutablePath
}
CGGradient — обект, определящ плавен преход между два или повече цвята по права линия (линеен градиент) или от центъра към ръбовете (радиален градиент). CGGradient се създава с указание на цветово пространство, масив от CGColorRef и масив от позиции на спиране от 0.0 до 1.0. След създаване градиентът може да се използва многократно в различни контексти.
CGShading — по-мощен механизъм, позволяващ задаване на функция за промяна на цвета по дължина на път. За разлика от CGGradient, който работи с фиксиран набор от цветове, CGShading използва callback функция (CGFunctionRef), изчисляваща цвета във всяка точка. Това позволява създаването на сложни градиенти с нелинейни преходи и сложни цветови схеми.
За рисуване на градиент във фигура е необходимо изрязване (clip) на контура на тази фигура. Ред: добавете пътя в контекста, извикайте CGContextClip, след това нарисувайте градиента. Без изрязване градиентът запълва целия контекст. В 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 !
// рисуване веднъж
layerCtx.setFillColor(UIColor.lightGray.cgColor)
layerCtx.addEllipse(in: CGRect(origin: .zero, size: size))
layerCtx.fillPath()
return layer
}
// използване в 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 }
// рисуване на фоново изображение
UIImage(named: "background")?.draw(in: rect)
// конфигуриране на прозрачност на воден знак
ctx.saveGState()
ctx.translateBy(x: rect.midX, y: rect.midY)
ctx.rotate(by: -.pi / 6)
// полупрозрачен текст
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
)
// векторна икона (кръг с кръст) под текста
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 документи. Можете да рисувате всяко CGContent директно върху PDF страница със запазване на векторите.
Core Graphics автоматично използва резолюцията на устройството при рендериране на екрана. За офлайн контексти използвайте UIGraphicsBeginImageContextWithOptions с параметър scale = 0 (системен мащаб) или изрично посочете 2.0/3.0 за Retina/Retina HD.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също