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 (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.
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).
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.
| Typ | Przeznaczenie | Zarządzanie pamięcią |
|---|---|---|
| CGContext | Kontekst graficzny | CFRelease lub automatyczne w Swift |
| CGPath | Kontur wektorowy | CFRelease (niezmienny) |
| CGColor | Kolor w przestrzeni kolorów | CFRelease lub CGColorCreate |
| CGImage | Obraz rastrowy | CFRelease (po utworzeniu) |
| CGLayer | Bufor offline | CFRelease lub CGLayerCreate |
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.
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.
// 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
}
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 — 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.
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 — 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 — 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.
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))
}
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.
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
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.
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.
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.
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.
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
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.
Przeczytaj również