Core Graphics è il framework di rendering 2D di Apple, parte di Core Foundation, disponibile su iOS, macOS, tvOS e watchOS. Fornisce un'API C di basso livello per lavorare con grafica vettoriale e raster, inclusi disegno di tracciati, gradienti, ombre, immagini e testo. Core Graphics funge da base per UIKit, SwiftUI e AppKit. Secondo Apple Developer Documentation, 2026, il framework è utilizzato in oltre il 90% delle app iOS, perché ogni elemento visibile passa attraverso Core Graphics o il suo equivalente hardware.
Punti chiave
Core Graphics (noto anche come Quartz 2D) è un framework che implementa il motore grafico 2D di Apple. È basato sulla libreria grafica portatile Quartz e utilizza un modello di disegno basato su pagine, dove ogni azione è un comando in una sequenza simile al disegno su carta. Core Graphics supporta l'anti-aliasing, la trasparenza (composizione alpha) e gli spazi colore ICC.
L'architettura di Core Graphics è costruita attorno a un contesto grafico (CGContext) che incapsula il dispositivo di output target — schermo, stampante, documento PDF o buffer raster. Il contesto gestisce le impostazioni correnti: colore, spessore della linea, trasformazione, area di ritaglio e font. Questo approccio fornisce un'API uniforme per diversi dispositivi di output senza modificare il codice di disegno.
Core Graphics funziona principalmente sulla CPU, utilizzando un modello vettoriale (indipendente dalla risoluzione). Ciò significa che linee e curve vengono rasterizzate alla risoluzione corrente del dispositivo durante il disegno. A differenza di Metal, Core Graphics non richiede una gestione esplicita delle risorse GPU — il sistema si occupa di tutta l'ottimizzazione. Per la maggior parte delle attività 2D (grafica, diagrammi, elementi UI personalizzati), le prestazioni di Core Graphics sono sufficienti per mantenere 60 FPS.
Core Graphics include circa 50 tipi base (tipi opachi), ciascuno responsabile di una funzionalità specifica. Tutti i tipi seguono le regole di gestione della memoria di Core Foundation: vengono creati tramite funzioni con Create nel nome, richiedono una chiamata a CGRelease e non sono compatibili ARC in Objective-C (tuttavia Swift gestisce automaticamente la memoria tramite annotazioni CF_RETURNS_RETAINED).
CGContext — il contesto di disegno, il tipo centrale del framework. CGPath — un tracciato vettoriale immutabile. CGColor — un colore con uno spazio colore specificato. CGGradient — un riempimento gradiente. CGImage — un'immagine raster. CGLayer — un buffer offline ottimizzato per il disegno ripetitivo. CGDataProvider — una fonte di dati per le immagini. CGColorSpace — uno spazio colore (sRGB, Display P3, Gray).
Ogni tipo è progettato per un overhead minimo: CGPath può essere memorizzato nella cache e riutilizzato tra diversi contesti, CGColor viene convertito in rappresentazione hardware GPU quando passato, CGLayer memorizza contenuti pre-rasterizzati. Questa architettura consente a Core Graphics di funzionare efficacemente sia in semplici attività UI che in editor grafici professionali.
| Tipo | Scopo | Gestione memoria |
|---|---|---|
| CGContext | Contesto grafico | CFRelease o automatico in Swift |
| CGPath | Tracciato vettoriale | CFRelease (immutabile) |
| CGColor | Colore nello spazio colore | CFRelease o CGColorCreate |
| CGImage | Immagine raster | CFRelease (dopo la creazione) |
| CGLayer | Buffer offline | CFRelease o CGLayerCreate |
CGPath è un oggetto immutabile che descrive una sequenza di segmenti geometrici: linee rette, curve di Bezier, archi e chiusure. A differenza di UIBezierPath, CGPath non contiene metodi di disegno — memorizza solo la geometria. Per disegnare, CGPath viene aggiunto al contesto (CGContextAddPath) e quindi renderizzato tramite strokePath o fillPath. L'immutabilità garantisce la sicurezza dei thread e la possibilità di caching.
CGPathCreateMutable crea un percorso mutabile (CGMutablePathRef) per la costruzione passo-passo. Dopo l'assemblaggio finale, viene convertito in un CGPathRef immutabile. Apple raccomanda di minimizzare il numero di punti in CGPath — tracciati troppo complessi (più di 1000 segmenti) rallentano la rasterizzazione. Per l'ottimizzazione, utilizzare CGPathCreateCopyBySimplifyingPath, che rimuove i punti collineari ridondanti.
Per animare la forma tra due oggetti CGPath, è possibile utilizzare CABasicAnimation sulla proprietà path di CAShapeLayer. Limitazione: entrambi i CGPath devono avere lo stesso numero di segmenti (punti di controllo). La funzione CGPathApply consente di attraversare tutti gli elementi del percorso e confrontare la loro struttura. Se i segmenti non corrispondono, l'animazione sarà a scatti — in questo caso, utilizzare CADisplayLink per l'interpolazione manuale dei punti.
// creare percorso mutabile
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()
// convertire in immutabile per caching sicuro
let immutablePath: CGPath = mutablePath
CATransaction.perform {
shapeLayer.path = immutablePath
}
CGGradient è un oggetto che definisce una transizione graduale tra due o più colori lungo una linea retta (gradiente lineare) o dal centro verso i bordi (gradiente radiale). CGGradient viene creato con uno spazio colore specificato, un array di CGColorRef e un array di posizioni di arresto da 0.0 a 1.0. Dopo la creazione, il gradiente può essere riutilizzato più volte in diversi contesti.
CGShading è un meccanismo più potente che consente di definire una funzione di cambiamento del colore lungo un percorso. A differenza di CGGradient, che lavora con un insieme fisso di colori, CGShading utilizza una funzione callback (CGFunctionRef) che calcola il colore in ogni punto. Ciò consente di creare gradienti complessi con transizioni non lineari e schemi di colore compositi.
Per disegnare un gradiente all'interno di una forma, è necessario un clip sul percorso di quella forma. L'ordine: aggiungere il percorso al contesto, chiamare CGContextClip, quindi disegnare il gradiente. Senza clip, il gradiente riempie l'intero contesto. Su iOS, si consiglia CGGradient come opzione più semplice e performante — CGShading è giustificato solo per funzioni di colore personalizzate.
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 è un'immagine raster in Core Graphics che può essere caricata da un file, creata programmaticamente o ottenuta da UIImage. CGImage contiene dati pixel, informazioni sullo spazio colore, dimensione, profondità di bit e disposizione dei dati. A differenza di UIImage, CGImage non gestisce il ridimensionamento Retina — questa responsabilità ricade sullo sviluppatore attraverso il parametro scale.
CGLayer è un buffer offline per la pre-rasterizzazione di contenuti statici. Se lo stesso insieme di comandi di disegno viene eseguito ripetutamente (ad esempio, un motivo di sfondo), CGLayer lo rasterizza una volta e poi lo copia semplicemente nel contesto. Secondo Apple, l'uso di CGLayer può accelerare il disegno ripetitivo di 2–5 volte sulla CPU e fino a 10 volte con accelerazione hardware.
Per caricare immagini, utilizzare CGImageSource — un'API potente per leggere metadati, miniature e singoli fotogrammi da GIF/APNG. CGImageSource consente il caricamento progressivo e il recupero solo dei frammenti necessari. Quando si lavora con immagini grandi (che superano le dimensioni dello schermo), si consiglia di creare un CGImageSource con caching su disco e utilizzare CGImageSourceCreateThumbnailAtIndex per visualizzare una versione ridotta.
func createLayer(ctx: CGContext, size: CGSize) -> CGLayer? {
guard let layer = CGLayer(ctx, size: size, auxiliaryInfo: nil) else { return nil }
let layerCtx = layer.context !
// disegnare una volta
layerCtx.setFillColor(UIColor.lightGray.cgColor)
layerCtx.addEllipse(in: CGRect(origin: .zero, size: size))
layerCtx.fillPath()
return layer
}
// utilizzo in draw()
for i in 0..<20 {
ctx.draw(layer, at: CGPoint(x: CGFloat(i) * 30, y: 0))
}
Costruiamo una View personalizzata per visualizzare una filigrana su un'immagine utilizzando Core Graphics. La filigrana include testo semi-trasparente e un logo vettoriale sovrapposti all'immagine originale. Il codice dimostra il lavoro con CGContext, CGImage, testo e trasparenza in un singolo contesto.
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 }
// disegnare immagine di sfondo
UIImage(named: "background")?.draw(in: rect)
// configurare trasparenza filigrana
ctx.saveGState()
ctx.translateBy(x: rect.midX, y: rect.midY)
ctx.rotate(by: -.pi / 6)
// testo semi-trasparente
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
)
// icona vettoriale (cerchio con croce) sotto il testo
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()
}
}
Il codice utilizza le funzionalità chiave di Core Graphics: saveGState/restoreGState per isolare gli effetti della filigrana dallo sfondo, translateBy e rotate per posizionamento e rotazione, testo semi-trasparente tramite withAlphaComponent e un'icona vettoriale tramite addEllipse e addLineTo. L'intera filigrana viene disegnata come una composizione unica dopo l'immagine di sfondo.
Quando si creano filigrane per foto in produzione, è importante considerare le prestazioni. Se l'immagine è più grande dello schermo, ridurla utilizzando CGImageSourceCreateThumbnailAtIndex prima di applicare la filigrana. Core Graphics gestisce tutte le operazioni sulla CPU — per l'elaborazione batch di dozzine di immagini, utilizzare una coda in background e CGBitmapContext per evitare di bloccare l'UI.
Domande frequenti
UIKit è un framework UI di alto livello che utilizza Core Graphics internamente per il disegno. Core Graphics è un'API C di basso livello per la grafica 2D. UIKit è più conveniente per gli elementi standard, mentre Core Graphics dà il controllo completo su ogni pixel.
Core Graphics è adatto per grafica 2D statica, diagrammi ed elementi UI personalizzati. Metal è per grafica 3D, animazioni complesse ed elaborazione di grandi array di pixel con accelerazione GPU. Per il 95% delle attività UI, Core Graphics è sufficiente.
Utilizzare CGImageSource per caricare miniature tramite createThumbnailAtIndex invece del caricamento completo. Per visualizzare immagini grandi, creare CGImage con l'opzione di downsampling. Rilasciare CGImage tramite CGImageRelease quando non è più necessario.
Sì, Core Graphics include il supporto completo PDF tramite CGPDFDocument per la lettura e CGPDFContext per la creazione di documenti PDF. È possibile disegnare qualsiasi contenuto CGContext direttamente in una pagina PDF preservando i vettori.
Core Graphics utilizza automaticamente la risoluzione del dispositivo quando disegna sullo schermo. Per contesti offline, utilizzare UIGraphicsBeginImageContextWithOptions con scale = 0 (scala di sistema) o specificare esplicitamente 2.0/3.0 per Retina/Retina HD.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche