Core Graphics — co to jest, zasady działania i framework do grafiki 2D

Autor: IT Sectr Opublikowano: 2026-07-21 Czas czytania: 10 min

Core Graphics — framework 2D-renderowania od Apple, wchodzący w skład Core Foundation i dostępny na iOS, macOS, tvOS i watchOS. Zapewnia niskopoziomowe C-API do pracy z grafiką wektorową i rastrową, w tym rysowanie konturów, gradientów, cieni, obrazów i tekstu. Core Graphics stanowi podstawę dla UIKit, SwiftUI i AppKit. Według danych Apple Developer Documentation, 2026, framework jest używany w ponad 90% aplikacji iOS, ponieważ każdy widoczny element przechodzi przez Core Graphics lub jego sprzętowy odpowiednik.

Najważniejsze

  • Core Graphics — fundamentalny framework 2D Apple do wektorowego i rastrowego renderowania.
  • CGContext — centralny obiekt frameworka, przez który wykonywane są wszystkie operacje rysowania.
  • CGPath — niezmienny kontur wektorowy do wielokrotnego użytku w różnych kontekstach.
  • CGGradient — obiekt do tworzenia liniowych i radialnych gradientów z obsługą przestrzeni kolorów.
  • CGImage — obraz rastrowy, który można rysować, transformować i maskować.

Czym jest Core Graphics?

Core Graphics (znany również jako Quartz 2D) — to framework implementujący 2D-graficzny silnik Apple. Jest oparty na przenośnej bibliotece graficznej Quartz i wykorzystuje model rysowania oparty na stronie (page-based), gdzie każde działanie to polecenie w sekwencji przypominającej rysowanie na papierze. Core Graphics obsługuje antyaliasing, przezroczystość (alpha compositing) i przestrzenie kolorów ICC.

Architektura Core Graphics zbudowana jest wokół kontekstu graficznego (CGContext), który hermetyzuje docelowe urządzenie wyjściowe — ekran, drukarkę, dokument PDF lub bufor rastrowy. Kontekst zarządza bieżącymi ustawieniami: kolorem, grubością linii, transformacją, obszarem przycinania i czcionkami. Takie podejście zapewnia jednolity API dla różnych urządzeń wyjściowych bez zmiany kodu rysowania.

Core Graphics działa głównie na CPU, wykorzystując model wektorowy (resolution-independent). Oznacza to, że linie i krzywe są rasteryzowane z bieżącą rozdzielczością urządzenia podczas renderowania. W przeciwieństwie do Metal, Core Graphics nie wymaga jawnego zarządzania zasobami GPU — całą optymalizację przejmuje system. Dla większości zadań 2D (grafika, diagramy, niestandardowe elementy UI) wydajność Core Graphics jest wystarczająca do utrzymania 60 FPS.

Architektura i główne typy

Core Graphics zawiera około 50 podstawowych typów (opaque types), z których każdy odpowiada za określoną funkcjonalność. Wszystkie typy przestrzegają zasad zarządzania pamięcią Core Foundation: tworzone są przez funkcje z Create w nazwie, wymagają wywołania CGRelease i nie są ARC-kompatybilne w Objective-C (jednak Swift automatycznie zarządza pamięcią przez adnotacje CF_RETURNS_RETAINED).

Kluczowe typy Core Graphics

CGContext — kontekst rysowania, centralny typ frameworka. CGPath — niezmienny kontur wektorowy. CGColor — kolor z określeniem przestrzeni kolorów. CGGradient — wypełnienie gradientowe. CGImage — obraz rastrowy. CGLayer — zoptymalizowany bufor offline do powtarzalnego rysowania. CGDataProvider — źródło danych dla obrazów. CGColorSpace — przestrzeń kolorów (sRGB, Display P3, Gray).

Każdy typ zaprojektowany jest z myślą o minimalnym narzucie: CGPath może być buforowany i współużywany między różnymi kontekstami, CGColor jest przekształcany do sprzętowej reprezentacji GPU przy przekazywaniu, CGLayer przechowuje wstępnie zrasteryzowaną zawartość. Taka architektura pozwala Core Graphics efektywnie pracować zarówno w prostych zadaniach UI, jak i w profesjonalnych edytorach graficznych.

TypPrzeznaczenieZarządzanie pamięcią
CGContextKontekst graficznyCFRelease lub automatyczne w Swift
CGPathKontur wektorowyCFRelease (niezmienny)
CGColorKolor w przestrzeni kolorówCFRelease lub CGColorCreate
CGImageObraz rastrowyCFRelease (po utworzeniu)
CGLayerBufor offlineCFRelease lub CGLayerCreate

CGPath: kontury wektorowe i ich optymalizacja

CGPath — niezmienny obiekt opisujący sekwencję geometrycznych segmentów: linii prostych, krzywych Béziera, łuków i zamknięć. W przeciwieństwie do UIBezierPath, CGPath nie zawiera metod rysowania — przechowuje tylko geometrię. Do rysowania CGPath dodawany jest do kontekstu (CGContextAddPath), a następnie rysowany przez strokePath lub fillPath. Niezmienność gwarantuje bezpieczeństwo wątków i możliwość buforowania.

Tworzenie i optymalizacja konturów

CGPathCreateMutable tworzy ścieżkę modyfikowalną (CGMutablePathRef) do stopniowego budowania. Po końcowym złożeniu przekształcana jest w niezmienny CGPathRef. Apple zaleca minimalizowanie liczby punktów w CGPath — zbyt złożone kontury (ponad 1000 segmentów) spowalniają rasteryzację. Do optymalizacji użyj CGPathCreateCopyBySimplifyingPath, który usuwa nadmiarowe współliniowe punkty.

Do animacji kształtu między dwoma CGPath można użyć CABasicAnimation na właściwości path CAShapeLayer. Ograniczenie: oba CGPath muszą mieć taką samą liczbę segmentów (controls points). Funkcja CGPathApply pozwala przejść przez wszystkie elementy ścieżki i porównać ich strukturę. Jeśli segmenty nie są zgodne, animacja będzie szarpana — w tym przypadku użyj CADisplayLink do ręcznej interpolacji punktów.

swift
// utwórz ścieżkę modyfikowalną
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()

// konwertuj na niezmienną dla bezpiecznego buforowania
let immutablePath: CGPath = mutablePath
CATransaction.perform {
    shapeLayer.path = immutablePath
}

Gradienty: CGGradient i CGShading

CGGradient — obiekt definiujący płynne przejście między dwoma lub więcej kolorami wzdłuż linii prostej (gradient liniowy) lub od środka do krawędzi (gradient radialny). CGGradient tworzony jest z określeniem przestrzeni kolorów, tablicy CGColorRef i tablicy pozycji zatrzymań od 0.0 do 1.0. Po utworzeniu gradient może być wielokrotnie używany w różnych kontekstach.

CGShading dla zaawansowanych gradientów

CGShading — bardziej wydajny mechanizm pozwalający na określenie funkcji zmiany koloru wzdłuż ścieżki. W przeciwieństwie do CGGradient, który działa ze stałym zestawem kolorów, CGShading używa funkcji zwrotnej (CGFunctionRef) obliczającej kolor w każdym punkcie. Pozwala to tworzyć złożone gradienty z nieliniowymi przejściami i złożonymi schematami kolorów.

Do rysowania gradientu wewnątrz figury konieczne jest clip na kontur tej figury. Kolejność: dodać ścieżkę do kontekstu, wywołać CGContextClip, następnie narysować gradient. Bez clip gradient wypełnia cały kontekst. W iOS zaleca się używanie CGGradient jako prostszej i bardziej wydajnej opcji — CGShading jest uzasadniony tylko dla niestandardowych funkcji zmiany koloru.

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

Praca z obrazami: CGImage i CGLayer

CGImage — obraz rastrowy w Core Graphics, który może być załadowany z pliku, utworzony programowo lub uzyskany z UIImage. CGImage zawiera dane pikseli, informacje o przestrzeni kolorów, rozmiarze, głębi bitowej i rozmieszczeniu danych. W przeciwieństwie do UIImage, CGImage nie zarządza skalowaniem dla Retina — tę odpowiedzialność przejmuje programista przez parametr scale.

CGLayer — optymalizacja powtarzalnego rysowania

CGLayer — bufor offline do wstępnej rasteryzacji statycznej zawartości. Jeśli ten sam zestaw poleceń graficznych jest rysowany wielokrotnie (np. wzór tła), CGLayer rasteryzuje go raz, a następnie po prostu kopiuje do kontekstu. Według danych Apple, użycie CGLayer może przyspieszyć powtarzalne rysowanie 2–5 razy na CPU i do 10 razy przy akceleracji sprzętowej.

Do ładowania obrazów używaj CGImageSource — potężnego API do odczytu metadanych, miniatur i poszczególnych klatek z GIF/APNG. CGImageSource pozwala ładować obraz progresywnie i pobierać tylko niezbędne fragmenty. Podczas pracy z dużymi obrazami (przekraczającymi rozmiar ekranu) zaleca się tworzenie CGImageSource z opcją buforowania na dysku i używanie CGImageSourceCreateThumbnailAtIndex do wyświetlania zmniejszonej wersji.

swift
func createLayer(ctx: CGContext, size: CGSize) -> CGLayer? {
    guard let layer = CGLayer(ctx, size: size, auxiliaryInfo: nil) else { return nil }
    let layerCtx = layer.context !

    // rysuj raz
    layerCtx.setFillColor(UIColor.lightGray.cgColor)
    layerCtx.addEllipse(in: CGRect(origin: .zero, size: size))
    layerCtx.fillPath()
    return layer
}

// użycie w draw()
for i in 0..<20 {
    ctx.draw(layer, at: CGPoint(x: CGFloat(i) * 30, y: 0))
}

Przykład pracy z Core Graphics

Opracujemy niestandardowy widok do wyświetlania znaku wodnego na obrazie z użyciem Core Graphics. Znak wodny zawiera półprzezroczysty tekst i wektorowe logo nałożone na oryginalny obraz. Kod demonstruje pracę z CGContext, CGImage, tekstem i przezroczystością w jednym kontekście.

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 }

        // rysuj obraz tła
        UIImage(named: "background")?.draw(in: rect)

        // skonfiguruj przezroczystość znaku wodnego
        ctx.saveGState()
        ctx.translateBy(x: rect.midX, y: rect.midY)
        ctx.rotate(by: -.pi / 6)

        // półprzezroczysty tekst
        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
        )

        // ikona wektorowa (okrąg z krzyżykiem) pod tekstem
        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()
    }
}

W kodzie użyto kluczowych możliwości Core Graphics: saveGState/restoreGState do izolacji efektów znaku wodnego od tła, translateBy i rotate do pozycjonowania i obrotu, półprzezroczysty tekst przez withAlphaComponent oraz wektorową ikonę przez addEllipse i addLineTo. Cały znak wodny rysowany jest jako jedna kompozycja po obrazie tła.

Przy tworzeniu znaków wodnych dla zdjęć w produkcji ważne jest uwzględnienie wydajności. Jeśli obraz jest większy od ekranu, przed nałożeniem znaku wodnego zmniejsz go przez CGImageSourceCreateThumbnailAtIndex. Core Graphics przetwarza wszystkie operacje na CPU — do wsadowego przetwarzania dziesiątek obrazów używaj kolejki tła i CGBitmapContext, aby uniknąć blokowania UI.

Często zadawane pytania

Czym Core Graphics różni się od UIKit?

UIKit — wysokopoziomowy framework UI, używający wewnętrznie Core Graphics do renderowania. Core Graphics — niskopoziomowe C-API do grafiki 2D. UIKit jest wygodniejszy dla standardowych elementów, Core Graphics daje pełną kontrolę nad każdym pikselem.

Kiedy używać Core Graphics zamiast Metal?

Core Graphics nadaje się do statycznej grafiki 2D, diagramów i niestandardowych elementów UI. Metal — do grafiki 3D, złożonych animacji i przetwarzania dużych tablic pikseli z akceleracją GPU. Dla 95% zadań UI wystarczy Core Graphics.

Jak zaoszczędzić pamięć podczas pracy z CGImage?

Używaj CGImageSource do ładowania miniatur przez createThumbnailAtIndex zamiast pełnego ładowania. Do wyświetlania dużych obrazów twórz CGImage z opcją downsample. Zwolnij CGImage przez CGImageRelease, gdy nie jest już potrzebny.

Czy Core Graphics obsługuje PDF?

Tak, Core Graphics zawiera pełną obsługę PDF przez CGPDFDocument do odczytu i CGPDFContext do tworzenia dokumentów PDF. Można rysować dowolną zawartość CGContext bezpośrednio na stronie PDF z zachowaniem wektorów.

Jak zapewnić jakość Retina podczas rysowania?

Core Graphics automatycznie używa rozdzielczości urządzenia podczas renderowania na ekranie. Do kontekstów offline używaj UIGraphicsBeginImageContextWithOptions z parametrem scale = 0 (skala systemowa) lub jawnie podaj 2.0/3.0 dla Retina/Retina HD.

Podsumowanie

  • Core Graphics — fundamentalny framework 2D Apple do wektorowego i rastrowego renderowania na CPU.
  • CGContext — centralny obiekt zarządzający stosem stanów i docelowym urządzeniem wyjściowym.
  • CGPath — niezmienne kontury wektorowe do bezpiecznego buforowania i współużytkowania między wątkami.
  • CGGradient i CGShading — mechanizmy tworzenia liniowych, radialnych i funkcyjnych gradientów.
  • CGImage — obrazy rastrowe z obsługą różnych przestrzeni kolorów i głębi bitowej.
  • CGLayer — bufor offline do przyspieszenia powtarzalnego rysowania 2–5 razy.
  • Core Graphics stanowi podstawę dla UIKit, SwiftUI i AppKit — każdy widoczny element w iOS przechodzi przez nią.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również