Search code examples
swiftcocoapdfquartz-graphics

Unable to draw into a new PDF with Cocoa/Swift/Quartz


I'm trying create a simple command line app with Swift that will create a new PDF, draw into it, and save the PDF to disk. Below is a bare-bones version of my code:

// main.swift
import Cocoa

let fileName = "test.pdf"

func getPath() -> NSURL? {
    let fileManager = NSFileManager.defaultManager()
    do {
        let dir = try fileManager.URLForDirectory(
          NSSearchPathDirectory.DocumentDirectory,
          inDomain: NSSearchPathDomainMask.UserDomainMask,
          appropriateForURL: nil,
          create: false
        )
        return dir.URLByAppendingPathComponent(fileName)
    } catch {
        return nil
    }
}

let context = CGPDFContextCreateWithURL(getPath(), nil, nil)
CGPDFContextBeginPage(context, nil)

let path = NSBezierPath(rect: NSRect(x: 0, y: 0, width: 100, height: 100))
NSColor.greenColor().set()
path.fill()

CGPDFContextEndPage(context)
CGPDFContextClose(context)

When running this code it creates a new test.pdf file in my ~/Documents directory, as expected, but it's just a blank 8.5x11 page. Any drawing code fails with this error: <Error>: CGContextSetFillColorWithColor: invalid context 0x0.

The code samples for creating and drawing into a PDF that I can find are all quite old. They certainly aren't Swift and they also tend to use Quartz C APIs so I'm feeling a bit lost at this point.

Thanks for reading.


Solution

  • You're mixing two worlds here. CoreGraphics and high-level Cocoa drawing calls. To make the Cocoa drawing work, you need to create an NSGraphicsContext based on the CoreGraphics one and make it the current context:

    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:true)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrentContext(graphicsContext)