2

I'm trying to create a CoreGraphics Context using the following MacOS Quartz API:

CGContext.init?(_ url: CFURL, 
                mediaBox: UnsafePointer<CGRect>?, 
                _ auxiliaryInfo: CFDictionary?)

, but I'm having trouble with the concept of pointers. I can initiate the context thus:

var mypointer: UnsafeMutablePointer<CGRect>!
mypointer.pointee = myCGRectangle
var writeContext = CGContext.init(outURL, mediaBox: mypointer, nil)

But it says that pointee is a get-only property. I've tried:

var mypointer: UnsafePointer<CGRect>! = UnsafePointer(myCGRectangle)

, based on this, but I get cannot convert CGRect to expected type, amongst other errors.

I have looked at several other questions here about pointers, but I can't find anything useful within them.

benwiggy
  • 1,440
  • 17
  • 35

2 Answers2

3

Just pass a reference to your myCGRectangle variable, this will create the needed UnsafeMutablePointer:

var writeContext = CGContext(outURL, mediaBox: &myCGRectangle, nil)

Make sure the rectangle variable is declared as var, otherwise the & won't work.

More details can be found on this excellent Apple documentation page about passing pointers to functions that require ones.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Thanks. Google had failed me for that Apple page. Don't see why the variable needs to be var, given that it's not actually changing, but there we are. – benwiggy Feb 07 '22 at 17:21
  • 1
    @benwiggy it needs to be a `var` as you're passing a pointer to that storage, a pointer that can be freely modified by the function you're calling. – Cristik Feb 07 '22 at 17:23
0

Typically you do not just create a variable of type UnsafeMutablePointer<CGRect> and pass it to the init(_:mediaBox:_:). You rather pass a rectangle for which PDF will be displayed, e.g.

var mediaBox = CGRect(x: 0, y: 0, width: 300, height: 500)
...
var writeContext = CGContext(outURL, mediaBox: &mediaBox, nil)

(even that is a simplification, as it creates a rectangle directly. Usually you have some rectangle of the view you want to display PDF in, so you will be passing that rectangle.)

You are also allowed to pass nil to the init(_:mediaBox:_:). In which case, as docs say:

If you pass NULL, CGPDFContextCreateWithURL uses a default page size of 8.5 by 11 inches (612 by 792 points).

So if that rectangle fits your needs, just pass nil (simpler).

timbre timbre
  • 12,648
  • 10
  • 46
  • 77
  • Sadly, I need the size to be adjustable. Thanks. – benwiggy Feb 07 '22 at 18:23
  • @benwiggy the size is always adjustable: here you only provide a default size. When you call `beginPage(mediaBox` you can always adjust it – timbre timbre Feb 07 '22 at 18:39
  • Yes, but beginPDFPage wants a pointer to a box too! – benwiggy Feb 08 '22 at 07:46
  • @benwiggy yes, and this is where you typically provide an actual frame you want to display PDF in. The initialization of `CGContext` is considered expensive, so you init it once (and can specify `nil` for frame - or something else, as you want), but then usually by the time you call `beginPage` you actually have a box to display in (with correct dimensions, which may not be available when you init `CGContext`. So this is where you pass your actual box, and as I said, you don't typically create it, but take existing frame of the view to display in – timbre timbre Feb 08 '22 at 14:08
  • When you say "expensive", do you mean time or memory? I'm creating a command line tool for manipulating PDF files, so no views or frames! But I already know the size at init time. – benwiggy Feb 08 '22 at 15:24