Core Graphics — що це, принципи роботи та фреймворк для 2D-графіки

Автор: IT Sectr Опубліковано: 2026-07-21 Час читання: 10 хв

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 — фундаментальний 2D-фреймворк Apple для векторного та растрового рендерингу.
  • CGContext — центральний об'єкт фреймворку, через який виконуються всі операції малювання.
  • CGPath — незмінний векторний контур для повторного використання в різних контекстах.
  • CGGradient — об'єкт для створення лінійних та радіальних градієнтів із підтримкою колірних просторів.
  • CGImage — растрове зображення, яке можна відмальовувати, трансформувати та маскувати.

Що таке Core Graphics?

Core Graphics (також відомий як Quartz 2D) — це фреймворк, що реалізує 2D-графічний рушій Apple. Він заснований на портативній графічній бібліотеці Quartz і використовує модель малювання на основі сторінки, де кожна дія — це команда в послідовності, що нагадує малювання на папері. Core Graphics підтримує антиаліасинг, прозорість (альфа-композитинг) та колірні простори ICC.

Архітектура Core Graphics побудована навколо графічного контексту (CGContext), який інкапсулює цільовий пристрій виведення — екран, принтер, PDF-документ або растровий буфер. Контекст керує поточними налаштуваннями: кольором, товщиною лінії, трансформацією, областю відсікання та шрифтами. Такий підхід забезпечує уніфікований API для різних пристроїв виведення без зміни коду малювання.

Core Graphics працює переважно на CPU, використовуючи векторну модель (незалежну від роздільної здатності). Це означає, що лінії та криві растерізуються з поточною роздільною здатністю пристрою під час відмальовування. На відміну від Metal, Core Graphics не вимагає явного керування GPU-ресурсами — всю оптимізацію бере на себе система. Для більшості 2D-задач (графіка, діаграми, кастомні елементи UI) продуктивності Core Graphics достатньо для підтримки 60 FPS.

Архітектура та основні типи

Core Graphics включає близько 50 базових типів (непрозорих типів), кожен з яких відповідає за певну функціональність. Усі типи дотримуються правил керування пам'яттю Core Foundation: створюються через функції з Create у назві, потребують виклику CGRelease і не є ARC-сумісними в Objective-C (однак Swift автоматично керує пам'яттю через анотації CF_RETURNS_RETAINED).

Ключові типи Core Graphics

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: векторні контури та їх оптимізація

CGPath — незмінний об'єкт, що описує послідовність геометричних сегментів: прямих ліній, кривих Безьє, дуг та замикань. На відміну від UIBezierPath, CGPath не містить методів малювання — він лише зберігає геометрію. Для відмальовування CGPath додається в контекст (CGContextAddPath) і потім малюється через strokePath або fillPath. Незмінність гарантує потокобезпеку та можливість кешування.

Створення та оптимізація контурів

CGPathCreateMutable створює змінюваний шлях (CGMutablePathRef) для поетапної побудови. Після фінального складання він перетворюється на незмінний CGPathRef. Apple рекомендує мінімізувати кількість точок у CGPath — надто складні контури (понад 1000 сегментів) сповільнюють растеризацію. Для оптимізації використовуйте CGPathCreateCopyBySimplifyingPath, який видаляє надлишкові колінеарні точки.

Для анімації форми між двома CGPath можна використовувати CABasicAnimation на властивості path CAShapeLayer. Обмеження: обидва CGPath повинні мати однакову кількість сегментів (контрольних точок). Функція CGPathApply дозволяє обійти всі елементи шляху та порівняти їх структуру. Якщо сегменти не збігаються, анімація буде сіпаною — у цьому випадку використовуйте CADisplayLink для ручної інтерполяції точок.

swift
// створити змінюваний шлях
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 та CGShading

CGGradient — об'єкт, що визначає плавний перехід між двома або більше кольорами вздовж прямої лінії (лінійний градієнт) або від центру до країв (радіальний градієнт). CGGradient створюється із зазначенням колірного простору, масиву CGColorRef та масиву позицій зупинок від 0.0 до 1.0. Після створення градієнт можна використовувати багаторазово в різних контекстах.

CGShading для розширених градієнтів

CGShading — потужніший механізм, що дозволяє задавати функцію зміни кольору вздовж шляху. На відміну від CGGradient, який працює з фіксованим набором кольорів, CGShading використовує callback-функцію (CGFunctionRef), що обчислює колір у кожній точці. Це дозволяє створювати складні градієнти з нелінійними переходами та складовими колірними схемами.

Для відмальовування градієнта всередині фігури необхідний clip на контур цієї фігури. Порядок: додати шлях у контекст, викликати CGContextClip, потім намалювати градієнт. Без clip градієнт заповнює весь контекст повністю. В iOS рекомендується використовувати CGGradient як простіший та продуктивніший варіант — CGShading виправданий лише для нестандартних функцій зміни кольору.

swift
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 та CGLayer

CGImage — растрове зображення в Core Graphics, яке може бути завантажене з файлу, створене програмно або отримане з UIImage. CGImage містить піксельні дані, інформацію про колірний простір, розмір, бітову глибину та розташування даних. На відміну від UIImage, CGImage не керує масштабуванням для Retina — цю відповідальність бере на себе розробник через параметр scale.

CGLayer — оптимізація повторюваного малювання

CGLayer — офлайн-буфер для попередньої растеризації статичного вмісту. Якщо один і той самий набір графічних команд відмальовується багаторазово (наприклад, патерн фону), CGLayer растерізує його один раз і потім просто копіює в контекст. За даними Apple, використання CGLayer може прискорити повторюване малювання в 2–5 разів на CPU та до 10 разів при апаратному прискоренні.

Для завантаження зображень використовуйте CGImageSource — потужний API для читання метаданих, мініатюр та окремих кадрів із GIF/APNG. CGImageSource дозволяє завантажувати зображення прогресивно та отримувати лише необхідні фрагменти. При роботі з великими зображеннями (що перевищують розмір екрану) рекомендується створювати CGImageSource з опцією кешування на диску та використовувати CGImageSourceCreateThumbnailAtIndex для відображення зменшеної версії.

swift
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))
}

Приклад роботи з Core Graphics

Розробимо кастомне View для відображення водяного знака на зображенні з використанням Core Graphics. Водяний знак включає напівпрозорий текст та векторний логотип, накладені поверх вихідного зображення. Код демонструє роботу з CGContext, CGImage, текстом та прозорістю в одному контексті.

swift
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.

Поширені запитання

Чим Core Graphics відрізняється від UIKit?

UIKit — високорівневий фреймворк UI, що використовує Core Graphics всередині себе для відмальовування. Core Graphics — низькорівневий C-API для 2D-графіки. UIKit зручніший для стандартних елементів, Core Graphics дає повний контроль над кожним пікселем.

Коли використовувати Core Graphics замість Metal?

Core Graphics підходить для статичної 2D-графіки, діаграм та кастомних UI-елементів. Metal — для 3D-графіки, складних анімацій та обробки великих масивів пікселів із GPU-прискоренням. Для 95% UI-задач достатньо Core Graphics.

Як заощадити пам'ять при роботі з CGImage?

Використовуйте CGImageSource для завантаження мініатюр через createThumbnailAtIndex замість повного завантаження. Для відображення великих зображень створюйте CGImage з опцією даунсемплу. Звільняйте CGImage через CGImageRelease коли він більше не потрібен.

Чи підтримує Core Graphics PDF?

Так, Core Graphics включає повноцінну підтримку PDF через CGPDFDocument для читання та CGPDFContext для створення PDF-документів. Можна малювати будь-який CGContext-контент прямо в PDF-сторінку зі збереженням векторів.

Як забезпечити Retina-якість при малюванні?

Core Graphics автоматично використовує роздільну здатність пристрою при відмальовуванні на екрані. Для офлайн-контекстів використовуйте UIGraphicsBeginImageContextWithOptions з параметром scale = 0 (системний масштаб) або явно вкажіть 2.0/3.0 для Retina/Retina HD.

Підсумки

  • Core Graphics — фундаментальний 2D-фреймворк Apple для векторного та растрового рендерингу на CPU.
  • CGContext — центральний об'єкт, що керує стеком станів та цільовим пристроєм виведення.
  • CGPath — незмінні векторні контури для безпечного кешування та потокобезпечного перевикористання.
  • CGGradient та CGShading — механізми створення лінійних, радіальних та функціональних градієнтів.
  • CGImage — растрові зображення з підтримкою різних колірних просторів та бітової глибини.
  • CGLayer — офлайн-буфер для прискорення повторюваного малювання в 2–5 разів.
  • Core Graphics слугує основою для UIKit, SwiftUI та AppKit — будь-який видимий елемент в iOS проходить через неї.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також