Core Graphics คือเฟรมเวิร์กการเรนเดอร์ 2D ของ Apple ซึ่งเป็นส่วนหนึ่งของ Core Foundation ที่พร้อมใช้งานบน iOS, macOS, tvOS และ watchOS โดยมี API ภาษา C ระดับต่ำสำหรับทำงานกับกราฟิกเวกเตอร์และแรสเตอร์ รวมถึงการวาดเส้นทาง เกรเดียนต์ เงา รูปภาพ และข้อความ Core Graphics ทำหน้าที่เป็นพื้นฐานสำหรับ UIKit, SwiftUI และ AppKit ตาม Apple Developer Documentation, 2026 เฟรมเวิร์กนี้ถูกใช้ในมากกว่า 90% ของแอป iOS เนื่องจากทุกองค์ประกอบที่มองเห็นได้ต้องผ่าน Core Graphics หรืออุปกรณ์เทียบเท่าทางฮาร์ดแวร์
ประเด็นสำคัญ
Core Graphics (หรือที่รู้จักในชื่อ Quartz 2D) คือเฟรมเวิร์กที่ implement เอนจินกราฟิก 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)
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 — เส้นทางที่ซับซ้อนเกินไป (มากกว่า 1,000 ส่วน) ทำให้การแรสเตอร์ช้าลง สำหรับการเพิ่มประสิทธิภาพ ให้ใช้ CGPathCreateCopyBySimplifyingPath ซึ่งลบจุดที่ซ้ำซ้อนที่อยู่บนเส้นตรงเดียวกัน
สำหรับการเคลื่อนไหวรูปร่างระหว่างออบเจ็กต์ CGPath สองตัว คุณสามารถใช้ CABasicAnimation บนคุณสมบัติ path ของ CAShapeLayer ข้อจำกัด: CGPath ทั้งสองต้องมีจำนวนส่วนเท่ากัน (จุดควบคุม) ฟังก์ชัน 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) ที่คำนวณสีในแต่ละจุด ซึ่งช่วยให้สร้างเกรเดียนต์ที่ซับซ้อนด้วยการเปลี่ยนแปลงที่ไม่เป็นเชิงเส้นและแบบแผนสีแบบผสม
ในการวาดเกรเดียนต์ภายในรูปทรง จำเป็นต้องมี คลิป บนเส้นทางของรูปทรงนั้น ลำดับ: เพิ่มเส้นทางไปยังบริบท เรียก 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 คือ API ภาษา C ระดับต่ำสำหรับกราฟิก 2D UIKit สะดวกกว่าสำหรับองค์ประกอบมาตรฐาน ในขณะที่ Core Graphics ให้ควบคุมทุกพิกเซลอย่างสมบูรณ์
Core Graphics เหมาะสำหรับกราฟิก 2D แบบคงที่ แผนภูมิ และองค์ประกอบ UI ที่กำหนดเอง Metal เหมาะสำหรับกราฟิก 3D อนิเมชันที่ซับซ้อน และการประมวลผลอาร์เรย์พิกเซลขนาดใหญ่ด้วยการเร่ง GPU สำหรับ 95% ของงาน UI Core Graphics ก็เพียงพอ
ใช้ CGImageSource เพื่อโหลดภาพขนาดย่อผ่าน createThumbnailAtIndex แทนการโหลดทั้งหมด ในการแสดงภาพขนาดใหญ่ ให้สร้าง CGImage พร้อมตัวเลือกลดตัวอย่าง ปล่อย CGImage ผ่าน CGImageRelease เมื่อไม่ต้องการใช้อีก
ใช่ Core Graphics รวมการรองรับ PDF อย่างสมบูรณ์ผ่าน CGPDFDocument สำหรับการอ่านและ CGPDFContext สำหรับการสร้างเอกสาร PDF คุณสามารถวาดเนื้อหา CGContext ใดๆ ลงในหน้า PDF โดยตรงโดยคงเวกเตอร์ไว้
Core Graphics ใช้ความละเอียดของอุปกรณ์โดยอัตโนมัติเมื่อวาดบนหน้าจอ สำหรับบริบทออฟไลน์ ให้ใช้ UIGraphicsBeginImageContextWithOptions ด้วย scale = 0 (สเกลระบบ) หรือระบุ 2.0/3.0 สำหรับ Retina/Retina HD อย่างชัดเจน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม